diff options
Diffstat (limited to '')
-rw-r--r-- | scripts/dau.pl | 5750 |
1 files changed, 5750 insertions, 0 deletions
diff --git a/scripts/dau.pl b/scripts/dau.pl new file mode 100644 index 0000000..ac8c051 --- /dev/null +++ b/scripts/dau.pl @@ -0,0 +1,5750 @@ +################################################################################ +# $Id: dau.pl 273 2008-02-03 15:27:25Z heidinger $ +################################################################################ +# +# dau.pl - write like an idiot +# +################################################################################ +# Author +################################################################################ +# +# Clemens Heidinger <heidinger@dau.pl> +# +################################################################################ +# Changelog +################################################################################ +# +# dau.pl has a built-in changelog (--changelog switch) +# +################################################################################ +# Credits +################################################################################ +# +# - Robert Hennig: For the original dau shell script. Out of this script, +# merged with some other small Perl and shell scripts and aliases arised the +# first version of dau.pl for irssi. +# +################################################################################ +# Documentation +################################################################################ +# +# dau.pl has a built-in documentation (--help switch) +# +################################################################################ +# License +################################################################################ +# +# Licensed under the BSD license +# +################################################################################ +# Website +################################################################################ +# +# http://dau.pl/ +# +# Additional information, DAU.pm, the dauomat and the dauproxy +# +################################################################################ + +use 5.6.0; +use File::Basename; +use File::Path; +use IPC::Open3; +use Irssi 20021107.0841; +use Irssi::TextUI; +use locale; +use POSIX; +use re 'eval'; +use strict; +use Tie::File; +use vars qw($VERSION %IRSSI); + +$VERSION = '2.4.3'; +#$VERSION = '2.4.3 SVN ($LastChangedRevision: 273 $)'; +%IRSSI = ( + authors => 'Clemens Heidinger', + changed => '$LastChangedDate: 2008-02-03 16:27:25 +0100 (Sun, 03 Feb 2008) $', + commands => 'dau', + contact => 'heidinger@dau.pl', + description => 'write like an idiot', + license => 'BSD', + modules => 'File::Basename File::Path IPC::Open3 POSIX Tie::File', + name => 'DAU', + sbitems => 'daumode', + url => 'http://dau.pl/', +); + +################################################################################ +# Register commands +################################################################################ + +Irssi::command_bind('dau', \&command_dau); + +################################################################################ +# Register settings +# setting changed/added => change/add it here +################################################################################ + +# boolean +Irssi::settings_add_bool('misc', 'dau_away_quote_reason', 1); +Irssi::settings_add_bool('misc', 'dau_away_reminder', 0); +Irssi::settings_add_bool('misc', 'dau_babble_verbose', 1); +Irssi::settings_add_bool('misc', 'dau_color_choose_colors_randomly', 1); +Irssi::settings_add_bool('misc', 'dau_cowsay_print_cow', 0); +Irssi::settings_add_bool('misc', 'dau_figlet_print_font', 0); +Irssi::settings_add_bool('misc', 'dau_silence', 0); +Irssi::settings_add_bool('misc', 'dau_statusbar_daumode_hide_when_off', 0); +Irssi::settings_add_bool('misc', 'dau_tab_completion', 1); + +# Integer +Irssi::settings_add_int('misc', 'dau_babble_history_size', 10); +Irssi::settings_add_int('misc', 'dau_babble_verbose_minimum_lines', 2); +Irssi::settings_add_int('misc', 'dau_cool_maximum_line', 2); +Irssi::settings_add_int('misc', 'dau_cool_probability_eol', 20); +Irssi::settings_add_int('misc', 'dau_cool_probability_word', 20); +Irssi::settings_add_int('misc', 'dau_remote_babble_interval_accuracy', 90); + +# String +Irssi::settings_add_str('misc', 'dau_away_away_text', '$N is away now: [ $reason ]. Away since: $Z. I am currently not available at $T @ $chatnet (sry 4 amsg)!'); +Irssi::settings_add_str('misc', 'dau_away_back_text', '$N is back: [ $reason ]. Away time: [ $time ]. I am available again at $T @ $chatnet (sry 4 amsg)!'); +Irssi::settings_add_str('misc', 'dau_away_options', + "--parse_special --bracket -left '!---?[' -right ']?---!' --color -split capitals -random off -codes 'light red; yellow'," . + "--parse_special --bracket -left '--==||{{' -right '}}||==--' --color -split capitals -random off -codes 'light red; light cyan'," . + "--parse_special --bracket -left '--==||[[' -right ']]||==--' --color -split capitals -random off -codes 'yellow; light green'" +); +Irssi::settings_add_str('misc', 'dau_away_reminder_interval', '1 hour'); +Irssi::settings_add_str('misc', 'dau_away_reminder_text', '$N is still away: [ $reason ]. Away time: [ $time ] (sry 4 amsg)'); +Irssi::settings_add_str('misc', 'dau_babble_options_line_by_line', '--nothing'); +Irssi::settings_add_str('misc', 'dau_babble_options_preprocessing', ''); +Irssi::settings_add_str('misc', 'dau_color_codes', 'blue; green; red; magenta; yellow; cyan'); +Irssi::settings_add_str('misc', 'dau_cool_eol_style', 'random'); +Irssi::settings_add_str('misc', 'dau_cowsay_cowlist', ''); +Irssi::settings_add_str('misc', 'dau_cowsay_cowpath', &def_dau_cowsay_cowpath); +Irssi::settings_add_str('misc', 'dau_cowsay_cowpolicy', 'allow'); +Irssi::settings_add_str('misc', 'dau_cowsay_cowsay_path', &def_dau_cowsay_cowsay_path); +Irssi::settings_add_str('misc', 'dau_cowsay_cowthink_path', &def_dau_cowsay_cowthink_path); +Irssi::settings_add_str('misc', 'dau_daumode_channels', ''); +Irssi::settings_add_str('misc', 'dau_delimiter_string', ' '); +Irssi::settings_add_str('misc', 'dau_figlet_fontlist', 'mnemonic,term,ivrit'); +Irssi::settings_add_str('misc', 'dau_figlet_fontpath', &def_dau_figlet_fontpath); +Irssi::settings_add_str('misc', 'dau_figlet_fontpolicy', 'allow'); +Irssi::settings_add_str('misc', 'dau_figlet_path', &def_dau_figlet_path); +Irssi::settings_add_str('misc', 'dau_files_away', '.away'); +Irssi::settings_add_str('misc', 'dau_files_babble_messages', 'babble_messages'); +Irssi::settings_add_str('misc', 'dau_files_cool_suffixes', 'cool_suffixes'); +Irssi::settings_add_str('misc', 'dau_files_root_directory', "$ENV{HOME}/.dau"); +Irssi::settings_add_str('misc', 'dau_files_substitute', 'substitute.pl'); +Irssi::settings_add_str('misc', 'dau_language', 'en'); +Irssi::settings_add_str('misc', 'dau_moron_eol_style', 'random'); +Irssi::settings_add_str('misc', 'dau_parse_special_list_delimiter', ' '); +Irssi::settings_add_str('misc', 'dau_random_options', + '--substitute --boxes --uppercase,' . + "--substitute --color -split capitals -random off -codes 'light red; yellow'," . + "--substitute --color -split capitals -random off -codes 'light red; light cyan'," . + "--substitute --color -split capitals -random off -codes 'yellow; light green'," . + '--substitute --color --uppercase,' . + '--substitute --cool,' . + '--substitute --delimiter,' . + '--substitute --dots --moron,' . + '--substitute --leet,' . + '--substitute --mix,' . + '--substitute --mixedcase --bracket,' . + '--substitute --moron --stutter --uppercase,' . + '--substitute --moron -omega on,' . + '--substitute --moron,' . + '--substitute --uppercase --underline,' . + '--substitute --words --mixedcase' +); +Irssi::settings_add_str('misc', 'dau_remote_babble_channellist', ''); +Irssi::settings_add_str('misc', 'dau_remote_babble_channelpolicy', 'deny'); +Irssi::settings_add_str('misc', 'dau_remote_babble_interval', '1 hour'); +Irssi::settings_add_str('misc', 'dau_remote_channellist', ''); +Irssi::settings_add_str('misc', 'dau_remote_channelpolicy', 'deny'); +Irssi::settings_add_str('misc', 'dau_remote_deop_reply', 'you are on my shitlist now @ $nick'); +Irssi::settings_add_str('misc', 'dau_remote_devoice_reply', 'you are on my shitlist now @ $nick'); +Irssi::settings_add_str('misc', 'dau_remote_op_reply', 'thx 4 op @ $nick'); +Irssi::settings_add_str('misc', 'dau_remote_permissions', '000000'); +Irssi::settings_add_str('misc', 'dau_remote_question_regexp', '%%%DISABLED%%%'); +Irssi::settings_add_str('misc', 'dau_remote_question_reply', 'EDIT_THIS_ONE'); +Irssi::settings_add_str('misc', 'dau_remote_voice_reply', 'thx 4 voice @ $nick'); +Irssi::settings_add_str('misc', 'dau_standard_messages', 'hi @ all'); +Irssi::settings_add_str('misc', 'dau_standard_options', '--random'); +Irssi::settings_add_str('misc', 'dau_words_range', '1-4'); + +################################################################################ +# Register signals +# (Note that most signals are set dynamical in the subroutine signal_handling) +################################################################################ + +Irssi::signal_add_last('setup changed', \&signal_setup_changed); +Irssi::signal_add_last('window changed' => sub { Irssi::statusbar_items_redraw('daumode') }); +Irssi::signal_add_last('window item changed' => sub { Irssi::statusbar_items_redraw('daumode') }); + +################################################################################ +# Register statusbar items +################################################################################ + +Irssi::statusbar_item_register('daumode', '', 'statusbar_daumode'); + +################################################################################ +# Global variables +################################################################################ + +# Timer used by --away + +our %away_timer; + +# babble + +our %babble; + +# --command -in + +our $command_in; + +# The command to use for the output (MSG f.e.) + +our $command_out; + +# '--command -out' used? + +our $command_out_activated; + +# Counter for the subroutines entered + +our $counter_subroutines; + +# Counter for the switches +# --me --moron: --me would be 0, --moron 1 + +our $counter_switches; + +# daumode + +our %daumode; + +# daumode activated? + +our $daumode_activated; + +# Help text + +our %help; +$help{options} = <<END; +%9--away%9 + Toggle away mode + + %9-channels%9 %U'#channel1/network1, #channel2/network2, ...'%U: + Say away message in all those %Uchannels%U + + %9-interval%9 %Utime%U: + Remind channel now and then that you're away + + %9-reminder%9 %Uon|off%U: + Turn reminder on or off + +%9--babble%9 + Babble a message. + + %9-at%9 %Unicks%U: + Comma separated list of nicks to babble at. + \$nick1, \$nick2 and so forth of the babble line will be replaced + by those nicks. + + %9-cancel%9 %Uon|off%U: + Cancel active babble + + %9-filter%9 %Uregular expression%U: + Only let through if the babble matches the %Uregular expression%U + + %9-history_size%9 %Un%U: + Set the size of the history for this one babble to %Un%U + +%9--boxes%9 + Put words in boxes + +%9--bracket%9 + Bracket the text + + %9-left%9 %Ustring%U: + Left bracket + + %9-right%9 %Ustring%U: + Right bracket + +%9--changelog%9 + Print the changelog + +%9--chars%9 + Only one character each line + +%9--color%9 + Write in colors + + %9-codes%9 %Ucodes%U: + Overrides setting dau_color_codes + + %9-random%9 %Uon|off%U: + Choose color randomly from setting dau_color_codes resp. + %9--color -codes%9 or take one by one in the exact order given. + + %9-split%9 + %Ucapitals%U: Split by capitals + %Uchars%U: Every character another color + %Ulines%U: Every line another color + %Uparagraph%U: The whole paragraph in one color + %Urchars%U: Some characters one color + %Uwords%U: Every word another color + +%9--command%9 + %9-in%9 %Ucommand%U: + Feed dau.pl with the output (the public message) + that %Ucommand%U produces + + %9-out%9 %Ucommand%U: + %Utopic%U for example will set a dauified topic + +%9--cool%9 + Be \$cool[tm]!!!!11one + + %9-eol_style%9 %Ustring%U: + Override setting dau_cool_eol_style + + %9-max%9 %Un%U: + \$Trademarke[tm] only %Un%U words per line tops + + %9-prob_eol%9 %U0-100%U: + Probability that "!!!11one" or something like that will be put at EOL. + Set it to 100 and every line will be. + Set it to 0 and no line will be. + + %9-prob_word%9 %U0-100%U: + Probability that a word will be \$trademarked[tm]. + Set it to 100 and every word will be. + Set it to 0 and no word will be. + +%9--cowsay%9 + Use cowsay to write + + %9-arguments%9 %Uarguments%U: + Pass any option to cowsay, f.e. %U'-b'%U or %U'-e XX'%U. + Look in the cowsay manualpage for details. + + %9-cow%9 %Ucow%U: + The cow to use + + %9-think%9 %Uon|off%U: + Thinking instead of speaking + +%9--create_files%9 + Create files and directories of all dau_files_* settings + +%9--daumode%9 + Toggle daumode. + Works on a per channel basis! + + %9-modes_in%9 %Umodes%U: + All incoming messages will be dauified and the + specified modes are used by dau.pl. + + %9-modes_out%9 %Umodes%U: + All outgoing messages will be dauified and the + specified modes are used by dau.pl. + + %9-perm%9 %U[01][01]%U: + Dauify incoming/outgoing messages? + +%9--delimiter%9 + Insert a delimiter-string after each character + + %9-string%9 %Ustring%U: + Override setting dau_delimiter_string. If this string + contains whitespace, you should quote the string with + single quotes. + +%9--dots%9 + Put dots... after words... + +%9--figlet%9 + Use figlet to write + + %9-font%9 %Ufont%U: + The font to use + +%9--help%9 + Print help + + %9-setting%9 %Usetting%U: + More information about a specific setting + +%9--leet%9 + Write in leet speech + +%9--long_help%9 + Long help, i.e. examples, more about some features, ... + +%9--me%9 + Send a CTCP ACTION instead of a PRIVMSG + +%9--mix%9 + Mix all the characters in a word except for the first and last + +%9--mixedcase%9 + Write in mixed case + +%9--moron%9 + Write in uppercase, mix in some typos, perform some + substitutions on the text, ... Just write like a + moron + + %9-eol_style%9 %Ustring%U: + Override setting dau_moron_eol_style + + %9-level%9 %Un%U: + %Un%U gives the level of stupidity applied to text, + the higher the stupider. + %U0%U is the minimum, %U1%U currently only implemented for dau_language = de. + + %9-omega%9 %Uon|off%U: + The fantastic omega mode + + %9-typo%9 %Uon|off%U: + Mix in random typos + + %9-uppercase%9 %Uon|off%U: + Uppercase text + +%9--nothing%9 + Do nothing + +%9--parse_special%9 + Parse for special metasequences and substitute them. + + %9-irssi_variables%9 %Uon|off%U: + Parse irssi special variables like \$N + + %9-list_delimiter%9 %Ustring%U: + Set the list delimiter used for \@nicks and \@opnicks to %Ustring%U. + + The special metasequences are: + + - \\n: + real newline + - \$nick1 .. \$nickN: + N different randomly selected nicks + - \@nicks: + All nicks in channel + - \$opnick1 .. \$opnickN: + N different randomly selected opnicks + - \@opnicks: + All nicks in channel with operator status + - \$?{ code }: + the (perl)code will be evaluated and the last expression + returned will replace that metasequence + - irssis special variables like \$C for the current + channel and \$N for your current nick + + Quoting: + + - \\\$: literal \$ + - \\\\: literal \\ + +%9--random%9 + Let dau.pl choose the options randomly. Get these options from the setting + dau_random_options. + + %9-verbose%9 %Uon|off%U: + Print what options --random has chosen + +%9--reverse%9 + Reverse the input string + +%9--stutter%9 + Stutter a bit + +%9--substitute%9 + Apply own substitutions from file + +%9--underline%9 + Underline text + +%9--uppercase%9 + Write in upper case + +%9--words%9 + Only a few words each line +END + +# Containing irssi's 'cmdchars' + +our $k = Irssi::parse_special('$k'); + +# Remember your nick mode + +our %nick_mode; + +# All the options + +our %option; + +# print() the message or not? + +our $print_message; + +# Queue holding the switches + +our %queue; + +# Remember the last switches used by --random so that they don't repeat + +our $random_last; + +# Signals + +our %signal = ( + 'complete word' => 0, + 'daumode in' => 0, + 'event 404' => 0, + 'event privmsg' => 0, + 'nick mode changed' => 0, + 'send text' => 0, +); + +# All switches that may be given at commandline + +our %switches = ( + + # These switches may be combined + + combo => { + boxes => { 'sub' => \&switch_boxes }, + bracket => { + 'sub' => \&switch_bracket, + left => { '*' => 1 }, + right => { '*' => 1 }, + }, + chars => { 'sub' => \&switch_chars }, + color => { + 'sub' => \&switch_color, + codes => { '*' => 1 }, + random => { + off => 1, + on => 1, + }, + 'split' => { + capitals => 1, + chars => 1, + lines => 1, + paragraph => 1, + rchars => 1, + words => 1, + }, + }, + command => { + 'sub' => \&switch_command, + in => { '*' => 1 }, + out => { '*' => 1 }, + }, + cool => { + 'sub' => \&switch_cool, + eol_style => { + suffixes => 1, + exclamation_marks => 1, + random => 1, + }, + max => { '*' => 1 }, + prob_eol => { '*' => 1 }, + prob_word => { '*' => 1 }, + }, + cowsay => { + 'sub' => \&switch_cowsay, + arguments => { '*' => 1 }, + think => { + off => 1, + on => 1, + }, + }, + delimiter => { + 'sub' => \&switch_delimiter, + string => { '*' => 1 }, + }, + dots => { 'sub' => \&switch_dots }, + figlet => { 'sub' => \&switch_figlet }, + me => { 'sub' => \&switch_me }, + mix => { 'sub' => \&switch_mix }, + moron => { + 'sub' => \&switch_moron, + eol_style => { + nothing => 1, + random => 1, + }, + level => { '*' => 1 }, + omega => { + off => 1, + on => 1, + }, + typo => { + off => 1, + on => 1, + }, + uppercase => { + off => 1, + on => 1, + }, + }, + leet => { 'sub' => \&switch_leet }, + mixedcase => { 'sub' => \&switch_mixedcase }, + nothing => { 'sub' => \&switch_nothing }, + parse_special => { + 'sub' => \&switch_parse_special, + irssi_variables => { + off => 1, + on => 1, + }, + list_delimiter => { '*' => 1 }, + }, + 'reverse' => { 'sub' => \&switch_reverse }, + stutter => { 'sub' => \&switch_stutter }, + substitute => { 'sub' => \&switch_substitute }, + underline => { 'sub' => \&switch_underline }, + uppercase => { 'sub' => \&switch_uppercase }, + words => { 'sub' => \&switch_words }, + }, + + # The following switches must not be combined + + nocombo => { + away => { + 'sub' => \&switch_away, + channels => { '*' => 1 }, + interval => { '*' => 1 }, + reminder => { + on => 1, + off => 1, + }, + }, + babble => { + 'sub' => \&switch_babble, + at => { '*' => 1 }, + cancel => { + on => 1, + off => 1, + }, + filter => { '*' => 1 }, + history_size => { '*' => 1 }, + }, + changelog => { 'sub' => \&switch_changelog }, + create_files => { 'sub' => \&switch_create_files }, + daumode => { + 'sub' => \&switch_daumode, + modes_in => { '*' => 1 }, + modes_out => { '*' => 1 }, + perm => { + '00' => 1, + '01' => 1, + '10' => 1, + '11' => 1, + }, + }, + help => { + 'sub' => \&switch_help, + + # setting changed/added => change/add it here + + setting => { + # boolean + dau_away_quote_reason => 1, + dau_away_reminder => 1, + dau_babble_verbose => 1, + dau_color_choose_colors_randomly => 1, + dau_cowsay_print_cow => 1, + dau_figlet_print_font => 1, + dau_silence => 1, + dau_statusbar_daumode_hide_when_off => 1, + dau_tab_completion => 1, + + # Integer + dau_babble_history_size => 1, + dau_babble_verbose_minimum_lines => 1, + dau_cool_maximum_line => 1, + dau_cool_probability_eol => 1, + dau_cool_probability_word => 1, + dau_remote_babble_interval_accuracy => 1, + + # String + dau_away_away_text => 1, + dau_away_back_text => 1, + dau_away_options => 1, + dau_away_reminder_interval => 1, + dau_away_reminder_text => 1, + dau_babble_options_line_by_line => 1, + dau_babble_options_preprocessing => 1, + dau_color_codes => 1, + dau_cool_eol_style => 1, + dau_cowsay_cowlist => 1, + dau_cowsay_cowpath => 1, + dau_cowsay_cowpolicy => 1, + dau_cowsay_cowsay_path => 1, + dau_cowsay_cowthink_path => 1, + dau_daumode_channels => 1, + dau_delimiter_string => 1, + dau_figlet_fontlist => 1, + dau_figlet_fontpath => 1, + dau_figlet_fontpolicy => 1, + dau_figlet_path => 1, + dau_files_away => 1, + dau_files_babble_messages => 1, + dau_files_cool_suffixes => 1, + dau_files_root_directory => 1, + dau_files_substitute => 1, + dau_language => 1, + dau_moron_eol_style => 1, + dau_parse_special_list_delimiter => 1, + dau_random_options => 1, + dau_remote_babble_channellist => 1, + dau_remote_babble_channelpolicy => 1, + dau_remote_babble_interval => 1, + dau_remote_channellist => 1, + dau_remote_channelpolicy => 1, + dau_remote_deop_reply => 1, + dau_remote_devoice_reply => 1, + dau_remote_op_reply => 1, + dau_remote_permissions => 1, + dau_remote_question_regexp => 1, + dau_remote_question_reply => 1, + dau_remote_voice_reply => 1, + dau_standard_messages => 1, + dau_standard_options => 1, + dau_words_range => 1, + }, + }, + long_help => { 'sub' => \&switch_long_help }, + random => { 'sub' => \&switch_random, + verbose => { + off => 1, + on => 1, + }, + }, + }, +); + +################################################################################ +# Code run once at start +################################################################################ + +print CLIENTCRAP "dau.pl $VERSION loaded. For help type %9${k}dau --help%9 or %9${k}dau --long_help%9"; + +signal_setup_changed(); +build_nick_mode_struct(); +signal_handling(); + +################################################################################ +# Subroutines (commands) +################################################################################ + +sub command_dau { + my ($data, $server, $witem) = @_; + my $output; + + $output = parse_text($data, $witem); + + unless (defined($server) && $server && $server->{connected}) { + $print_message = 1; + } + unless ((defined($witem) && $witem && + ($witem->{type} eq 'CHANNEL' || $witem->{type} eq 'QUERY'))) + { + $print_message = 1; + } + + if ($daumode_activated) { + + if (defined($witem) && $witem && + ($witem->{type} eq 'CHANNEL' || $witem->{type} eq 'QUERY')) + { + my $modes_set = 0; + + # daumode set with parameters (modes_in) + + if ($queue{0}{daumode}{modes_in}) { + $daumode{channels_in}{$server->{tag}}{$witem->{name}} = 1; + $daumode{channels_in_modes}{$server->{tag}}{$witem->{name}} = + $queue{0}{daumode}{modes_in}; + $modes_set = 1; + } + + # daumode set with parameters (modes_out) + + if ($queue{0}{daumode}{modes_out}) { + $daumode{channels_out}{$server->{tag}}{$witem->{name}} = 1; + $daumode{channels_out_modes}{$server->{tag}}{$witem->{name}} = + $queue{0}{daumode}{modes_out}; + $modes_set = 1; + } + + # daumode set without parameters + + if (!$daumode{channels_in}{$server->{tag}}{$witem->{name}} && + !$daumode{channels_out}{$server->{tag}}{$witem->{name}} && + !$modes_set) + { + $daumode{channels_in}{$server->{tag}}{$witem->{name}} = 1; + $daumode{channels_out}{$server->{tag}}{$witem->{name}} = 1; + $daumode{channels_in_modes}{$server->{tag}}{$witem->{name}} = ''; + $daumode{channels_out_modes}{$server->{tag}}{$witem->{name}} = ''; + } + + # daumode unset + + elsif (($daumode{channels_in}{$server->{tag}}{$witem->{name}} || + $daumode{channels_out}{$server->{tag}}{$witem->{name}}) && + !$modes_set) + { + $daumode{channels_in}{$server->{tag}}{$witem->{name}} = 0; + $daumode{channels_out}{$server->{tag}}{$witem->{name}} = 0; + $daumode{channels_in_modes}{$server->{tag}}{$witem->{name}} = ''; + $daumode{channels_out_modes}{$server->{tag}}{$witem->{name}} = ''; + } + + + # the perm-option overrides everything + + # perm: 00 + + if ($queue{0}{daumode}{perm} eq '00') { + $daumode{channels_in}{$server->{tag}}{$witem->{name}} = 0; + $daumode{channels_out}{$server->{tag}}{$witem->{name}} = 0; + $daumode{channels_in_modes}{$server->{tag}}{$witem->{name}} = ''; + $daumode{channels_out_modes}{$server->{tag}}{$witem->{name}} = ''; + } + + # perm: 01 + + if ($queue{0}{daumode}{perm} eq '01') { + $daumode{channels_in}{$server->{tag}}{$witem->{name}} = 0; + $daumode{channels_out}{$server->{tag}}{$witem->{name}} = 1; + $daumode{channels_in_modes}{$server->{tag}}{$witem->{name}} = ''; + } + + # perm: 10 + + if ($queue{0}{daumode}{perm} eq '10') { + $daumode{channels_in}{$server->{tag}}{$witem->{name}} = 1; + $daumode{channels_out}{$server->{tag}}{$witem->{name}} = 0; + $daumode{channels_out_modes}{$server->{tag}}{$witem->{name}} = ''; + } + + # perm: 11 + + if ($queue{0}{daumode}{perm} eq '11') { + $daumode{channels_in}{$server->{tag}}{$witem->{name}} = 1; + $daumode{channels_out}{$server->{tag}}{$witem->{name}} = 1; + } + + Irssi::statusbar_items_redraw('daumode'); + } + + # Signal handling (for daumode and signal 'send text') + + signal_handling(); + + return; + } + + # MSG (or CTCP ACTION) $output to active channel/query-window + + { + no strict 'refs'; + + $output = $output || ''; + output_text($witem, $witem->{name}, $output); + } +} + +################################################################################ +# Subroutines (switches, must not be combined) +################################################################################ + +sub switch_away { + my ($reason, $channel_rec, $reminder, $interval) = @_; + my $output; + my $time; + my $status = 'away'; + + ################################################################################ + ################################################################################ + # Get and handle options + ################################################################################ + ################################################################################ + + ################################################################################ + # "/dau --away -interval <interval>" resp. dau_away_reminder_interval setting + ################################################################################ + + # If called from command line, i.e. not by the + # "/dau --away -channels '<channels>'" workaround, $interval will be defined + # here + if (!defined($interval)) { + $interval = time_parse(return_option('away', 'interval', $option{dau_away_reminder_interval})); + } + if ($interval < 10 || $interval > 1000000000) { + print_err('Invalid value for away timer!'); + return; + } + + ################################################################################ + # setting dau_away_options + ################################################################################ + + my $options = return_random_list_item($option{dau_away_options}); + + ################################################################################ + # "/dau --away -reminder <on|off>" resp. dau_away_reminder setting + ################################################################################ + + # If called from command line, i.e. not by "/dau --away -channels '<channels>'" + # workaround, $reminder will be defined here + if (!defined($reminder)) { + $reminder = return_option('away', 'reminder', $option{dau_away_reminder}); + } + + # on -> 1, off -> 0 + if ($reminder eq 'on' || $reminder == 1) { + $reminder = 1; + } else { + $reminder = 0; + } + + ################################################################################ + # "/dau --away -channels '<channels>'" + ################################################################################ + + # Go through all channels and for each call this subroutine again with + # $reminder and $interval as additional parameter as those otherwise would be + # lost. Sad world. + + my $channels = return_option('away', 'channels'); + # If not deleted, the program may loop here. + undef($queue{0}{away}{channels}); + while ($channels =~ m{([^/]+)/([^,]+),?\s*}g) { + my $channel = $1; + my $network = $2; + + my $server_rec = Irssi::server_find_tag($network); + my $channel_rec = $server_rec->channel_find($channel); + + if (defined($channel_rec) && $channel_rec && + ($channel_rec->{type} eq 'CHANNEL' || $channel_rec->{type} eq 'QUERY')) + { + switch_away($reason, $channel_rec, $reminder, $interval); + } + + } + # "/dau --away -channels '<channels>'" first run => exit + return if ($channels); + + ################################################################################ + # Now we are clear (from -channels)... + ################################################################################ + + # Normal "/dau --away" (i.e. no -channels), but called from non + # channel/query window => exit + unless (defined($channel_rec) && $channel_rec && + ($channel_rec->{type} eq 'CHANNEL' || $channel_rec->{type} eq 'QUERY')) + { + return; + } + + my $channel = $channel_rec->{name}; + my $network = $channel_rec->{server}->{tag}; + my $id = "$channel/$network"; + + ################################################################################ + # Open file + ################################################################################ + + my $file = "$option{dau_files_root_directory}/$option{dau_files_away}"; + my @file; + unless (tie(@file, 'Tie::File', $file)) { + print_err("Cannot tie $file!"); + return; + } + + ################################################################################ + # Go through/edit file + ################################################################################ + + # Format: + # channel | network | time | options | reminder | interval | reason + my $i = 0; + foreach my $line (@file) { + if ($line =~ m{^\Q$channel\E\x02\Q$network\E\x02(\d+)\x02([^\x02]*)\x02(?:\d)\x02(?:\d+)\x02(.*)}) { + $time = $1; + $options = $2; + $reason = $3; + $status = 'back'; + last; + } + $i++; + } + + if ($status eq 'away' && $reason eq '') { + print_out('Please set reason for your being away!'); + return; + } + + if ($status eq 'away') { + push(@file, "$channel\x02$network\x02" . time . "\x02$options\x02$reminder\x02$interval\x02$reason"); + $output = $option{dau_away_away_text}; + } + + if ($status eq 'back') { + splice(@file, $i, 1); + $output = $option{dau_away_back_text}; + } + + ################################################################################ + # Special variables + ################################################################################ + + # $time + + if ($status eq 'back') { + my $difference = time_diff_verbose(time, $time); + $output =~ s/\$time/$difference/g; + } + + # $reason + + if ($option{dau_away_quote_reason}) { + $reason =~ s/\\/\\\\/g; + $reason =~ s/\$/\\\$/g; + } + $output =~ s/\$reason/$reason/g; + + ################################################################################ + # Write changes back to file + ################################################################################ + + untie(@file); + + ################################################################################ + # The reminder timer + ################################################################################ + + if ($status eq 'away' && $reminder) { + $away_timer{$id} = Irssi::timeout_add($interval, \&timer_away_reminder, $id); + } else { + Irssi::timeout_remove($away_timer{$id}); + } + + ################################################################################ + # Print message to channel + ################################################################################ + + $output = parse_text("$options $output", $channel_rec); + output_text($channel_rec, $channel_rec->{name}, $output); + + return; +} + +sub switch_babble { + my ($data, $channel) = @_; + my $text; + + # Cancel babble? + + if (lc(return_option('babble', 'cancel')) eq 'on') { + if (defined($babble{timer_writing})) { + Irssi::timeout_remove($babble{timer_writing}); + undef($babble{timer_writing}); + + if ($babble{remote}) { + timer_remote_babble_reset(); + } + + print_out("Babble cancelled."); + } + return; + } + + # Filters + + my @filter = (); + my $option_babble_at = return_option('babble', 'at'); + my $option_babble_filter = return_option('babble', 'filter'); + my $option_babble_history_size = return_option('babble', 'history_size', $option{dau_babble_history_size}); + + if ($option_babble_filter) { + push(@filter, $option_babble_filter); + } + + # If something is babbling right now, exit + + if (defined($babble{timer_writing})) { + print_err("You are already babbling something!"); + return; + } + + # get text from file + + if ($option_babble_at) { + my @nicks; + foreach my $nick (split(/\s*,\s*/, $option_babble_at)) { + push(@nicks, $nick); + } + if (@nicks > 0) { + for (my $i = 1; $i <= $#nicks + 1; $i++) { + push(@filter, '\$nick' . $i); + } + } + + $text = &babble_get_text($channel, \@filter, \@nicks, $option_babble_history_size); + } else { + $text = &babble_get_text($channel, \@filter, undef, $option_babble_history_size); + } + + # babble only in channels + + unless (defined($channel) && $channel && $channel->{type} eq 'CHANNEL') { + print_out('%9--babble%9 will only work in channel windows!'); + return; + } + + # Start the babbling + + babble_start($channel, $text, 0); + + return; +} + +sub switch_changelog { + my $output; + $print_message = 1; + + $output = &fix(<<" END"); + CHANGELOG + + 2002-05-05 release 0.1.0 + initial release + + 2002-05-06 release 0.1.1 + maintenance release + + 2002-05-11 release 0.2.0 + new feature: %9--delimiter%9 + + 2002-05-12 release 0.3.0 + new feature: %9--mixedcase%9 + + 2002-05-17 release 0.4.0 + %9--delimiter%9 revised + + 2002-05-20 release 0.4.1 + some nice new substitutions for %9--moron%9 + + 2002-05-24 release 0.5.0 + new settings for %9--figlet%9 + + 2002-06-15 release 0.6.0 + new settings for %9--figlet%9 + + 2002-06-16 release 0.6.1 + maintenance release + + 2002-06-16 release 0.6.2 + maintenance release + + 2002-06-17 release 0.7.0 + new stuff for %9--moron%9 + + 2002-06-19 release 0.8.0 + new feature: %9--dots%9 + + 2002-06-23 release 0.9.0 + new "reply to question" remote feature + + 2002-06-23 release 0.9.1 + maintenance release + + 2002-06-29 release 0.9.2 + maintenance release + + 2002-07-23 release 0.9.3 + maintenance release + + 2002-07-28 release 1.0.0 + - Tabcompletion for the switches + - new feature: %9--changelog%9 + - new feature: %9--help%9 + - new feature: %9--leet%9 + - new feature: %9--reverse%9 + + 2002-07-28 release 1.0.1 + maintenance release + + 2002-09-01 release 1.0.2 + maintenance release + + 2002-09-03 release 1.0.3 + new switch for %9--figlet%9: %9-font%9 + + 2002-09-03 release 1.0.4 + maintenance release + + 2002-09-03 release 1.0.5 + maintenance release + + 2002-09-09 release 1.1.0 + You can combine switches now! + + 2002-11-22 release 1.2.0 + - new setting: %9dau_moron_eol_style%9 + - new setting: %9dau_standard_messages%9 + - new setting: %9dau_standard_options%9 + - new remote features: Say something on (de)op/(de)voice + - new switch for %9--delimiter%9: %9-string%9 + - new switch for %9--moron%9: %9-eol_style%9 + - new feature: %9--color%9 + - new feature: %9--daumode%9 + - new feature: %9--random%9 + - new feature: %9--stutter%9 + - new feature: %9--uppercase%9 + - new statusbar item: %9daumode%9 + + 2002-11-27 release 1.2.1 + maintenance release + + 2002-12-15 release 1.2.2 + maintenance release + + 2003-01-12 release 1.3.0 + - new setting: %9dau_files_root_directory%9 + - %9--moron%9: randomly transpose letters with letters + next to them at the keyboard + - new switch for %9--moron%9: %9-uppercase%9 + - new feature: %9--create_files%9 + + 2003-01-17 release 1.4.0 + - %9--color%9 revised + - new remote feature: babble + + 2003-01-18 release 1.4.1 + maintenance release + + 2003-01-20 release 1.4.2 + new setting: %9dau_statusbar_daumode_hide_when_off%9 + + 2003-02-01 release 1.4.3 + maintenance release + + 2003-02-09 release 1.4.4 + maintenance release + + 2003-02-16 release 1.4.5 + maintenance release + + 2003-03-16 release 1.4.6 + maintenance release + + 2003-05-01 release 1.5.0 + - new setting: %9dau_tab_completion%9 + - new feature: %9--bracket%9 + + 2003-06-13 release 1.5.1 + new feature: %9--underline%9 + + 2003-07-16 release 1.5.2 + new feature: %9--boxes%9 + + 2003-08-16 release 1.5.3 + maintenance release + + 2003-09-14 release 1.5.4 + maintenance release + + 2003-11-16 release 1.6.0 + - Incoming messages can be dauified now! + - daumode statusbar item revised + + 2004-03-25 release 1.7.0 + - new setting: %9dau_babble_options_line_by_line%9 + - new setting: %9dau_files_babble_messages%9 + - new switch for %9--color%9: %9-split paragraph%9 + - new switch for %9--command%9: %9-in%9 + - new switch for %9--moron%9: %9-omega%9 + - new feature: %9--cowsay%9 + - new feature: %9--mix%9 (by Martin Kihlgren <zond\@troja.ath.cx>) + + 2004-04-01 release 1.7.1 + - new setting: %9dau_remote_babble_channellist%9 + - new setting: %9dau_remote_babble_channelpolicy%9 + - new setting: %9dau_remote_babble_interval_accuracy%9 + + 2004-04-02 release 1.7.2 + maintenance release + + 2004-04-05 release 1.7.3 + maintenance release + + 2004-05-01 release 1.8.0 + - new feature: %9--babble%9 + - %9--help%9 revised + + 2004-06-24 release 1.8.1 + - new setting: %9dau_babble_verbose%9 + - new setting: %9dau_babble_verbose_minimum_lines%9 + + 2004-07-10 release 1.8.2 + maintenance release + + 2004-07-25 release 1.8.3 + maintenance release + + 2004-09-14 release 1.8.4 + maintenance release + + 2004-10-18 release 1.8.5 + maintenance release + + 2004-11-07 release 1.8.6 + maintenance release + + 2005-01-28 release 1.9.0 + - new setting: %9dau_cowsay_cowthink_path%9 + - new switch for %9--cowsay%9: %9-arguments%9 + - new switch for %9--cowsay%9: %9-think%9 + + 2005-06-05 release 2.0.0 + - new setting: %9dau_color_choose_colors_randomly%9 + - new setting: %9dau_color_codes%9 + - new setting: %9dau_language%9 + - new setting: %9dau_remote_question_regexp%9 + - new switch for %9--bracket%9: %9-left%9 + - new switch for %9--bracket%9: %9-right%9 + - new switch for %9--color%9: %9-codes%9 + - new switch for %9--color%9: %9-random%9 + - new switch for %9--color%9: %9-split capitals%9 + - new feature: %9--away%9 + - new feature: %9--cool%9 + - new feature: %9--long_help%9 + - new feature: %9--parse_special%9 + + 2005-07-01 release 2.1.0 + - new switch for %9--babble%9: %9-at%9 + - %9--color%9: Support for background colors + - %9--color -codes%9: You may use now the color names + instead of the numeric color codes + + 2005-07-24 release 2.1.1 + maintenance release + + 2005-08-02 release 2.1.2 + maintenance release + + 2005-11-01 release 2.1.3 + maintenance release + + 2006-03-11 release 2.1.4 + maintenance release + + 2006-05-21 release 2.1.5 + new switch for %9--babble%9: %9-filter%9 + + 2006-10-25 release 2.1.6 + new switch for %9--babble%9: %9-cancel%9 + + 2006-11-25 release 2.2.0 + new feature: %9--substitute%9 + + 2007-03-07 release 2.3.0 + - new setting: %9dau_daumode_channels%9 + - new switch for %9--moron%9: %9-level%9 + - new switch for %9--moron%9: %9-typo%9 + - new switch for %9--random%9: %9-verbose%9 + + 2007-03-08 release 2.3.1 + maintenance release + + 2007-03-11 release 2.3.2 + maintenance release + + 2007-03-18 release 2.3.3 + maintenance release + + 2007-06-02 release 2.4.0 + - new setting: %9dau_babble_history_size%9 + - new switch for %9--babble%9: %9-history_size%9 + + 2007-06-26 release 2.4.1 + maintenance release + + 2007-10-11 release 2.4.2 + maintenance release + + 2008-02-03 release 2.4.3 + maintenance release + END + + return $output; +} + +sub switch_create_files { + + # create directory dau_files_root_directory if not found + + if (-f $option{dau_files_root_directory}) { + print_err("$option{dau_files_root_directory} is a _file_ => aborting"); + return; + } + if (-d $option{dau_files_root_directory}) { + print_out('directory dau_files_root_directory already exists - no need to create it'); + } else { + if (mkpath([$option{dau_files_root_directory}])) { + print_out("creating directory $option{dau_files_root_directory}/"); + } else { + print_err("failed creating directory $option{dau_files_root_directory}/"); + } + } + + # create file dau_files_substitute if not found + + my $file1 = "$option{dau_files_root_directory}/$option{dau_files_substitute}"; + + if (-e $file1) { + + print_out("file $file1 already exists - no need to create it"); + + } else { + + if (open(FH1, ">", $file1)) { + + print FH1 &fix(<<' END'); + # dau.pl - http://dau.pl/ + # + # This is the file --moron will use for your own substitutions. + # You can use any perlcode in here. + # $_ contains the text you can work with. + # $_ has to contain the data to be returned to dau.pl at the end. + END + + print_out("$file1 created. you should edit it now!"); + + } else { + + print_err("cannot write $file1: $!"); + + } + + if (!close(FH1)) { + print_err("cannot close $file1: $!"); + } + } + + # create file dau_files_babble_messages if not found + + my $file2 = "$option{dau_files_root_directory}/$option{dau_files_babble_messages}"; + + if (-e $file2) { + + print_out("file $file2 already exists - no need to create it"); + + } else { + + if (open(FH1, ">", $file2)) { + + print FH1 &fix(<<' END'); + END + + print_out("$file2 created. you should edit it now!"); + + } else { + + print_err("cannot write $file2: $!"); + + } + + if (!close(FH1)) { + print_err("cannot close $file2: $!"); + } + } + + # create file dau_files_cool_suffixes if not found + + my $file3 = "$option{dau_files_root_directory}/$option{dau_files_cool_suffixes}"; + + if (-e $file3) { + + print_out("file $file3 already exists - no need to create it"); + + } else { + + if (open(FH1, ">", $file3)) { + + print FH1 &fix(<<' END'); + END + + print_out("$file3 created. you should edit it now!"); + + } else { + + print_err("cannot write $file3: $!"); + + } + + if (!close(FH1)) { + print_err("cannot close $file3: $!"); + } + } + + return; +} + +sub switch_daumode { + $daumode_activated = 1; +} + +sub switch_help { + my $output; + my $option_setting = return_option('help', 'setting'); + $print_message = 1; + + if ($option_setting eq '') { + $output = &fix(<<" END"); + %9OPTIONS%9 + + $help{options} + END + } + + # setting changed/added => change/add them below + + # boolean + + elsif ($option_setting eq 'dau_away_quote_reason') { + $output = &fix(<<" END"); + %9dau_away_quote_reason%9 %Ubool + + If turned on, %9--parse_special%9 will not be able to replace + variables which probably aren't one anyway. + END + } + elsif ($option_setting eq 'dau_away_reminder') { + $output = &fix(<<" END"); + %9dau_away_reminder%9 %Ubool + + Turn the reminder message of %9--away%9 on or off. + END + } + elsif ($option_setting eq 'dau_babble_verbose') { + $output = &fix(<<" END"); + %9dau_babble_verbose%9 %Ubool + + Before babbling print a message how many lines will be babbled and + when finished a notification message. + END + } + elsif ($option_setting eq 'dau_color_choose_colors_randomly') { + $output = &fix(<<" END"); + %9dau_color_choose_colors_randomly%9 %Ubool + + Choose colors randomly from setting dau_color_codes resp. + %9--color -codes%9 or take one by one in the exact order given. + END + } + elsif ($option_setting eq 'dau_cowsay_print_cow') { + $output = &fix(<<" END"); + %9dau_cowsay_print_cow%9 %Ubool + + Print a message which cow will be used. + END + } + elsif ($option_setting eq 'dau_figlet_print_font') { + $output = &fix(<<" END"); + %9dau_figlet_print_font%9 %Ubool + + Print a message which font will be used. + END + } + elsif ($option_setting eq 'dau_silence') { + $output = &fix(<<" END"); + %9dau_silence%9 %Ubool + + Don't print any information message. This does not include + error messages. + END + } + elsif ($option_setting eq 'dau_statusbar_daumode_hide_when_off') { + $output = &fix(<<" END"); + %9dau_statusbar_daumode_hide_when_off%9 %Ubool + + Hide statusbar item when daumode is turned off. + END + } + elsif ($option_setting eq 'dau_tab_completion') { + $output = &fix(<<" END"); + %9dau_tab_completion%9 %Ubool + + Perhaps someone wants to disable TAB completion for the + ${k}dau-command because he/she doesn't like it or wants + to give the CPU a break (don't know whether it has much + influence) + END + } + + # Integer + + elsif ($option_setting eq 'dau_babble_history_size') { + $output = &fix(<<" END"); + %9dau_babble_history_size%9 %Uinteger + + Number of lines to store in the babble history. + dau.pl will babble no line the history is holding. + END + } + elsif ($option_setting eq 'dau_babble_verbose_minimum_lines') { + $output = &fix(<<" END"); + %9dau_babble_verbose_minimum_lines%9 %Uinteger + + Minimum lines necessary to produce the output of the verbose + information. + END + } + elsif ($option_setting eq 'dau_cool_maximum_line') { + $output = &fix(<<" END"); + %9dau_cool_maximum_line%9 %Uinteger + + Trademarke[tm] or do \$this only %Un%U words per line tops. + END + } + elsif ($option_setting eq 'dau_cool_probability_eol') { + $output = &fix(<<" END"); + %9dau_cool_probability_eol%9 %Uinteger + + Probability that "!!!11one" or something like that will be put at EOL. + Set it to 100 and every line will be. + Set it to 0 and no line will be. + END + } + elsif ($option_setting eq 'dau_cool_probability_word') { + $output = &fix(<<" END"); + %9dau_cool_probability_word%9 %Uinteger + + Probability that a word will be trademarked[tm]. + Set it to 100 and every word will be. + Set it to 0 and no word will be. + END + } + elsif ($option_setting eq 'dau_remote_babble_interval_accuracy') { + $output = &fix(<<" END"); + %9dau_remote_babble_interval_accuracy%9 %Uinteger + + Value expressed as a percentage how accurate the timer of + the babble feature should be. + + Legal values: 1-100 + + %U100%U would result in a very accurate timer. + END + } + + # String + + elsif ($option_setting eq 'dau_away_away_text') { + $output = &fix(<<" END"); + %9dau_away_away_text%9 %Ustring + + The text to say when using %9--away%9. + + Special Variables: + + \$reason: Your away reason. + END + } + elsif ($option_setting eq 'dau_away_back_text') { + $output = &fix(<<" END"); + %9dau_away_back_text%9 %Ustring + + The text to say when you return. + + Special Variables: + + \$reason: Your away reason. + \$time: The time you've been away. + END + } + elsif ($option_setting eq 'dau_away_reminder_interval') { + $output = &fix(<<" END"); + %9dau_away_reminder_interval%9 %Ustring + + Remind the channel that you're away! Repeat the message + in the given interval. + END + } + elsif ($option_setting eq 'dau_away_reminder_text') { + $output = &fix(<<" END"); + %9dau_away_reminder_text%9 %Ustring + + The text to say when you remind the channel that you're away. + + Special Variables: + + \$reason: Your away reason. + \$time: The time you've been away. + END + } + elsif ($option_setting eq 'dau_away_options') { + $output = &fix(<<" END"); + %9dau_away_options%9 %Ustring + + Options %9--away%9 will use. + END + } + elsif ($option_setting eq 'dau_babble_options_line_by_line') { + $output = &fix(<<" END"); + %9dau_babble_options_line_by_line%9 %Ustring + + One single babble may contain several lines. The options + specified in this setting are used for every line. + END + } + elsif ($option_setting eq 'dau_babble_options_preprocessing') { + $output = &fix(<<" END"); + %9dau_babble_options_preprocessing%9 %Ustring + + The options specified in this setting are applied to the + whole babble before anything else. Later, the options of + the setting %9dau_babble_options_line_by_line%9 are + applied to every line of the babble. + END + } + elsif ($option_setting eq 'dau_color_codes') { + $output = &fix(<<" END"); + %9dau_color_codes%9 %Ustring + + Specify the color codes to use, seperated by semicolons. + Example: %Ugreen; red; blue%U. You may use the color code (one + or two digits) or the color names. So either + %U2%U or %Ublue%U is ok. You can set a background color too: + %Ured,green%U and you will write with red on a green + background. + For a complete list of the color codes and names look at + formats.txt in the irssi documentation. + END + } + elsif ($option_setting eq 'dau_cool_eol_style') { + $output = &fix(<<" END"); + %9dau_cool_eol_style%9 %Ustring + + %Uexclamation_marks%U: !!!11one + %Urandom%U: Choose one style randomly + %Usuffixes%U: Suffixes from file + END + } + elsif ($option_setting eq 'dau_cowsay_cowlist') { + $output = &fix(<<" END"); + %9dau_cowsay_cowlist%9 %Ustring + + Comma separated list of cows. Checkout + %9${k}dau --help -setting dau_cowsay_cowpolicy%9 + to see what this setting is good for. + END + } + elsif ($option_setting eq 'dau_cowsay_cowpath') { + $output = &fix(<<" END"); + %9dau_cowsay_cowpath%9 %Ustring + + Path to the cowsay-cows (*.cow). + END + } + elsif ($option_setting eq 'dau_cowsay_cowpolicy') { + $output = &fix(<<" END"); + %9dau_cowsay_cowpolicy%9 %Ustring + + Specifies the policy used to handle the cows in + dau_cowsay_cowpath. If set to %Uallow%U, all cows available + will be used by the command. You can exclude some cows by + setting dau_cowsay_cowlist. If set to %Udeny%U, no cows but + the ones listed in dau_cowsay_cowlist will be used by the + command. Useful if you have many annoying cows in your + cowpath and you want to permit only a few of them. + END + } + elsif ($option_setting eq 'dau_cowsay_cowsay_path') { + $output = &fix(<<" END"); + %9dau_cowsay_cowsay_path%9 %Ustring + + Should point to the cowsay executable. + END + } + elsif ($option_setting eq 'dau_cowsay_cowthink_path') { + $output = &fix(<<" END"); + %9dau_cowsay_cowthink_path%9 %Ustring + + Should point to the cowthink executable. + END + } + elsif ($option_setting eq 'dau_daumode_channels') { + $output = &fix(<<" END"); + %9dau_daumode_channels%9 %U<channel>/<network>:<switches>, ...%U + + Automatically enable the daumode for some channels. + %U#foo/bar:-modes_out '--substitute'%U would automatically + set the daumode on #foo in network bar to modify outgoing + messages with --substitute. + END + } + elsif ($option_setting eq 'dau_delimiter_string') { + $output = &fix(<<" END"); + %9dau_delimiter_string%9 %Ustring + + Tell %9--delimiter%9 which delimiter to use. + END + } + elsif ($option_setting eq 'dau_figlet_fontlist') { + $output = &fix(<<" END"); + %9dau_figlet_fontlist%9 %Ustring + + Comma separated list of fonts. Checkout + %9${k}dau --help -setting dau_figlet_fontpolicy%9 + to see what this setting is good for. Use the program + `showfigfonts` shipped with figlet to find these fonts. + END + } + elsif ($option_setting eq 'dau_figlet_fontpath') { + $output = &fix(<<" END"); + %9dau_figlet_fontpath%9 %Ustring + + Path to the figlet-fonts (*.flf). + END + } + elsif ($option_setting eq 'dau_figlet_fontpolicy') { + $output = &fix(<<" END"); + %9dau_figlet_fontpolicy%9 %Ustring + + Specifies the policy used to handle the fonts in + dau_figlet_fontpath. If set to %Uallow%U, all fonts available + will be used by the command. You can exclude some fonts by + setting dau_figlet_fontlist. If set to %Udeny%U, no fonts but + the ones listed in dau_figlet_fontlist will be used by the + command. Useful if you have many annoying fonts in your + fontpath and you want to permit only a few of them. + END + } + elsif ($option_setting eq 'dau_figlet_path') { + $output = &fix(<<" END"); + %9dau_figlet_path%9 %Ustring + + Should point to the figlet executable. + END + } + elsif ($option_setting eq 'dau_files_away') { + $output = &fix(<<" END"); + %9dau_files_away%9 %Ustring + + The file with the away messages. + _Must_ be in dau_files_root_directory. + END + } + elsif ($option_setting eq 'dau_files_babble_messages') { + $output = &fix(<<" END"); + %9dau_files_babble_messages%9 %Ustring + + The file with the babble messages. + _Must_ be in dau_files_root_directory. + %9${k}dau --create_files%9 will create it. + + Format of the file: Newline separated plain text. + The text will be sent through %9--parse_special%9 as well. + END + } + elsif ($option_setting eq 'dau_files_cool_suffixes') { + $output = &fix(<<" END"); + %9dau_files_cool_suffixes%9 %Ustring + + %9--cool%9 takes randomly one line out of this file + and puts it at the end of the line. + This file _must_ be in dau_files_root_directory. + %9${k}dau --create_files%9 will create it. + + Format of the file: Newline separated plain text. + END + } + elsif ($option_setting eq 'dau_files_root_directory') { + $output = &fix(<<" END"); + %9dau_files_root_directory%9 %Ustring + + Directory in which all files for dau.pl will be stored. + %9${k}dau --create_files%9 will create it. + END + } + elsif ($option_setting eq 'dau_files_substitute') { + $output = &fix(<<" END"); + %9dau_files_substitute%9 %Ustring + + Your own substitutions file. _Must_ be in + dau_files_root_directory. + %9${k}dau --create_files%9 will create it. + END + } + elsif ($option_setting eq 'dau_language') { + $output = &fix(<<" END"); + %9dau_language%9 %Ustring + + %Ude%U: If you are writing in german + %Uen%U: If you are writing in english + END + } + elsif ($option_setting eq 'dau_moron_eol_style') { + $output = &fix(<<" END"); + %9dau_moron_eol_style%9 %Ustring + + What to do at End Of Line? + + %Urandom%U: + - !!!??!!!!!????!??????????!!!1 + - = + ? + - ?¿? + %Unothing%U: do nothing + END + } + elsif ($option_setting eq 'dau_parse_special_list_delimiter') { + $output = &fix(<<" END"); + %9dau_parse_special_list_delimiter%9 %Ustring + + Set the list delimiter used for \@nicks and \@opnicks to %Ustring%U. + END + } + elsif ($option_setting eq 'dau_random_options') { + $output = &fix(<<" END"); + %9dau_random_options%9 %Ustring + + Comma separated list of options %9--random%9 will use. It will + take randomly one item of the list. If you set it f.e. to + %U--uppercase --color,--mixedcase%U, + the probability of printing a colored, uppercased string hello + will be 50% as well as the probabilty of printing a mixedcased + string hello when typing %9${k}dau --random hello%9. + END + } + elsif ($option_setting eq 'dau_remote_babble_channellist') { + $output = &fix(<<" END"); + %9dau_remote_babble_channellist%9 %Ustring + + Comma separated list of channels. You'll have to specify the + ircnet too. + Format: #channel1/IRCNet,#channel2/EFnet + END + } + elsif ($option_setting eq 'dau_remote_babble_channelpolicy') { + $output = &fix(<<" END"); + %9dau_remote_babble_channelpolicy%9 %Ustring + + Using the default policy %Udeny%U the script won't do anything + except in the channels listed in dau_remote_babble_channellist. + Using the policy %Uallow%U the script will babble in all + channels but the ones listed in dau_remote_babble_channellist. + END + } + elsif ($option_setting eq 'dau_remote_babble_interval') { + $output = &fix(<<" END"); + %9dau_remote_babble_interval%9 %Ustring + + dau.pl will babble text in the given interval. + END + } + elsif ($option_setting eq 'dau_remote_channellist') { + $output = &fix(<<" END"); + %9dau_remote_channellist%9 %Ustring + + Comma separated list of channels. You'll have to specify the + ircnet too. + Format: #channel1/IRCNet,#channel2/EFnet + END + } + elsif ($option_setting eq 'dau_remote_channelpolicy') { + $output = &fix(<<" END"); + %9dau_remote_channelpolicy%9 %Ustring + + Using the default policy %Udeny%U the script won't do anything + except in the channels listed in dau_remote_channellist. Using + the policy %Uallow%U the script will reply to all channels but + the ones listed in dau_remote_channellist. + END + } + elsif ($option_setting eq 'dau_remote_deop_reply') { + $output = &fix(<<" END"); + %9dau_remote_deop_reply%9 %Ustring + + Comma separated list of messages (it will take randomly one + item of the list) sent to channel if someone deops you (mode + change -o). + The string given will be processed by the same subroutine + parsing the %9${k}dau%9 command. + + Special Variables: + + \$nick: contains the nick of the one who changed the mode + END + } + elsif ($option_setting eq 'dau_remote_devoice_reply') { + $output = &fix(<<" END"); + %9dau_remote_devoice_reply%9 %Ustring + + Comma separated list of messages (it will take randomly one + item of the list) sent to channel if someone devoices you (mode + change -v). + The string given will be processed by the same subroutine + parsing the %9${k}dau%9 command. + + Special Variables: + + \$nick: contains the nick of the one who changed the mode + END + } + elsif ($option_setting eq 'dau_remote_op_reply') { + $output = &fix(<<" END"); + %9dau_remote_op_reply%9 %Ustring + + Comma separated list of messages (it will take randomly one + item of the list) sent to channel if someone ops you (mode + change +o). + The string given will be processed by the same subroutine + parsing the %9${k}dau%9 command. + + Special Variables: + + \$nick: contains the nick of the one who changed the mode + END + } + elsif ($option_setting eq 'dau_remote_permissions') { + $output = &fix(<<" END"); + %9dau_remote_permissions%9 %U[01][01][01][01][01][01] + + Permit or forbid the remote features. + + First Bit: + Reply to question + + Second Bit: + If someone gives you voice in a channel, thank him! + + Third Bit: + If someone gives you op in a channel, thank him! + + Fourth Bit: + If devoiced, print message + + Fifth Bit: + If deopped, print message + + Sixth Bit: + Babble text in certain intervals + END + } + elsif ($option_setting eq 'dau_remote_question_regexp') { + $output = &fix(<<" END"); + %9dau_remote_question_regexp%9 %Ustring + + If someone says something matching that regular expression, + act accordingly. + The regexp will be sent through %9--parse_special%9. + Because of that you will have to escape some characters, f.e. + \\s to \\\\s for whitespace. + END + } + elsif ($option_setting eq 'dau_remote_question_reply') { + $output = &fix(<<" END"); + %9dau_remote_question_reply%9 %Ustring + + Comma separated list of reply strings for the question of + setting dau_remote_question_regexp (it will randomly choose one + item of the list). + The string given will be processed by the same subroutine + parsing the %9${k}dau%9 command. + + Special Variables: + + \$nick: contains the nick of the one who sent the message to which + dau.pl reacts + END + } + elsif ($option_setting eq 'dau_remote_voice_reply') { + $output = &fix(<<" END"); + %9dau_remote_voice_reply%9 %Ustring + + Comma separated list of messages (it will take randomly one + item of the list) sent to channel if someone voices you (mode + change +v). + The string given will be processed by the same subroutine + parsing the %9${k}dau%9 command. + + Special Variables: + + \$nick: contains the nick of the one who changed the mode + END + } + elsif ($option_setting eq 'dau_standard_messages') { + $output = &fix(<<" END"); + %9dau_standard_messages%9 %Ustring + + Comma separated list of strings %9${k}dau%9 will use if the user + omits the text on the commandline. + END + } + elsif ($option_setting eq 'dau_standard_options') { + $output = &fix(<<" END"); + %9dau_standard_options%9 %Ustring + + Options %9${k}dau%9 will use if the user omits them on the commandline. + END + } + elsif ($option_setting eq 'dau_words_range') { + $output = &fix(<<" END"); + %9dau_words_range%9 %Ui-j + + Setup the range howmany words the command should write per line. + 1 <= i <= j <= 9; i, j element { 1, ... , 9 }. If i == j the command + will write i words to the active window. Else it takes a random + number k (element { i, ... , j }) and writes k words per + line. + END + } + + return $output; +} + +sub switch_long_help { + my $output; + $print_message = 1; + + $output = &fix(<<" END"); + %9SYNOPSIS%9 + + %9${k}dau [%Uoptions%U] [%Utext%U%9] + + %9DESCRIPTION%9 + + dau? What does that mean? It's a german acronym for %9d%9ümmster + %9a%9nzunehmender %9u%9ser. In english: stupidest imaginable user. + + With dau.pl every person can write like an idiot on the IRC! + + %9OPTIONS%9 + + $help{options} + %9EXAMPLES%9 + + %9${k}dau --uppercase --mixedcase %Ufoo bar baz%9 + Will write %Ufoo bar baz%U in mixed case. + %Ufoo bar baz%U is sent _first_ to %9--uppercase%9, _then_ to + %9--mixedcase%9. + The order in which you put the options on the commandline is + important! + You can see what output a command produces without sending it to + the active channel/query by sending it to a non-channel/query + window. + + %9${k}dau --color --figlet %Ufoo bar baz%9 + %9--color%9 is the first to be run and thus color codes will + be inserted. + The string will look like %U\\00302f\\00303o[...]%U when leaving + %9--color%9. + %9--figlet%9 uses then that string as its input. + So you'll have finally an output like + %U02f03o[...]%U in the figlet letters. + You'll probably want to use %9--figlet --color%9 instead. + + %9SPECIAL FEATURES%9 + + %9Combine the options%9 + You can combine most of the options! So you can write colored + leet messages f.e.. Look in the EXAMPLES section above. + + %9Babble%9 + dau.pl will babble text for you. It can do this on its own + in certain intervals or forced by the user using %9--babble%9. + + Related settings: + + %9dau_babble_options_line_by_line%9 + %9dau_files_babble_messages%9 + %9dau_files_root_directory%9 + %9dau_remote_babble_channellist%9 + %9dau_remote_babble_channelpolicy%9 + %9dau_remote_babble_interval%9 + %9dau_remote_babble_interval_accuracy%9 + %9dau_remote_permissions%9 + + Related switches: + + %9--babble%9 + %9--create_files%9 + + %9Daumode%9 + Dauify incoming and/or outgoing messages. + + There is a statusbar item available displaying the current + status of the daumode. Add it with + %9/statusbar <bar> add [-alignment <left|right>] daumode%9 + You may customize the look of the statusbar item in the + theme file: + + sb_daumode = "{sb daumode I: \$0 (\$1) O: \$2 (\$3)}"; + + # \$0: will incoming messages be dauified? + # \$1: modes for incoming messages + # \$2: will outgoing messages be dauified? + # \$3: modes for outgoing messages + + %9Remote features%9 + Don't worry, dau.pl won't do anything automatically unless you + unlock these features! + + %9Babble%9 + dau.pl will babble text for you in certain intervals. + + %9Reply to a question%9 + Answer a question as a moron would. + + Related settings: + + %9dau_remote_channellist%9 + %9dau_remote_channelpolicy%9 + %9dau_remote_permissions%9 + %9dau_remote_question_regexp%9 + %9dau_remote_question_reply%9 + + %9Say something on (de)op/(de)voice%9 + Related settings: + + %9dau_remote_channellist%9 + %9dau_remote_channelpolicy%9 + %9dau_remote_deop_reply%9 + %9dau_remote_devoice_reply%9 + %9dau_remote_op_reply%9 + %9dau_remote_permissions%9 + %9dau_remote_voice_reply%9 + + %9TAB Completion%9 + There is a really clever TAB Completion included! Since + commands can get very long you definitely want to use it. + It will only complete syntactically correct commands so the + TAB Completion isn't only a time saver, it's a control + instance too. You'll be suprised to see that it even completes + the figlet fonts and cows for cowsay that are available on + your system. + + %9Website%9 + $IRSSI{url}: + Additional information, DAU.pm, the dauomat and the dauproxy. + END + + return $output; +} + +sub switch_random { + my ($data, $channel_rec) = @_; + my $output; + my (@options, $opt, $text); + + # Push each item of dau_random_options in the @options array. + + while ($option{dau_random_options} =~ /\s*([^,]+)\s*,?/g) { + my $item = $1; + push @options, $item; + } + + # More than one item in @options. Choose one randomly but exclude + # the last item chosen. + + if (@options > 1) { + @options = grep { $_ ne $random_last } @options; + $opt = @options[rand(@options)]; + $random_last = $opt; + } + + # Exact one item in @options - take that + + elsif (@options == 1) { + $opt = $options[0]; + $random_last = $opt; + } + + + # No item in @options - call switch_moron() + + else { + $opt = '--moron'; + } + + # dauify it! + + unless (lc(return_option('random', 'verbose')) eq 'off') { + print_out("%9--random%9 has chosen %9$opt%9", $channel_rec); + } + $text .= $opt . ' ' . $data; + $output = parse_text($text, $channel_rec); + + return $output; +} + +################################################################################ +# Subroutines (switches, may be combined) +################################################################################ + +sub switch_boxes { + my $data = shift; + + # handling punctuation marks: + # they will be put in their own box later + + $data =~ s%(\w+)([,.?!;:]+)% + $1 . ' ' . join(' ', split(//, $2)) + %egx; + + # separate words (by whitespace) and put them in a box + + $data =~ s/(\s*)(\S+)(\s*)/$1\[$2\]$3/g; + + return $data; +} + +sub switch_bracket { + my $data = shift; + my $output; + + my $option_left = return_option('bracket', 'left'); + my $option_right = return_option('bracket', 'right'); + + my %brackets = ( + '((' => '))', + '-=(' => ')=-', + '-=[' => ']=-', + '-={' => '}=-', + '-=|(' => ')|=-', + '-=|[' => ']|=-', + '-=|{' => '}|=-', + '.:>' => '<:.', + ); + + foreach (keys %brackets) { + for my $times (2 .. 3) { + my $pre = $_; + my $post = $brackets{$_}; + $pre =~ s/(.)/$1 x $times/eg; + $post =~ s/(.)/$1 x $times/eg; + + $brackets{$pre} = $post; + } + } + + $brackets{'!---?['} = ']?---!'; + $brackets{'(qp=>'} = '<=qp)'; + $brackets{'----->'} = '<-----'; + + my ($left, $right); + if ($option_left && $option_right) { + $left = $option_left; + $right = $option_right; + } else { + $left = (keys(%brackets))[int(rand(keys(%brackets)))]; + $right = $brackets{$left}; + } + + $output = "$left $data $right"; + + return $output; +} + +sub switch_chars { + my $data = shift; + my $output; + + foreach my $char (split //, $data) { + $output .= "$char\n"; + } + return $output; +} + +sub switch_command { + my ($data, $channel_rec) = @_; + + # -out <command> + + $command_out = return_option('command', 'out'); + $command_out_activated = 1; + + # -in <command> + + $command_in = ''; + my $option_command_in = return_option('command', 'in'); + + if ($option_command_in) { + return unless (defined($channel_rec) && $channel_rec); + + # Deactivate daumode for a brief moment + $signal{'send text'} = 0; + Irssi::signal_remove('send text', 'signal_send_text'); + + # Capture the output + Irssi::signal_add_first('command msg', 'signal_command_msg'); + $channel_rec->command("$option_command_in $data"); + Irssi::signal_remove('command msg', 'signal_command_msg'); + + # Reactivate daumode + signal_handling(); + + return $command_in; + } + + return $data; +} + +sub switch_color { + my $data = shift; + my (@all_colors, @colors, $output, $split); + + ################################################################################ + # Hack to support UTF-8 + ################################################################################ + + if (Irssi::settings_get_str('term_charset') =~ /utf-?8/i) { + eval { + require Encode; + $data = Encode::decode("utf-8", $data); + }; + } + + ################################################################################ + # Get options + ################################################################################ + + my $option_color_split = return_option('color', 'split', 'words'); + my $option_color_codes = return_option('color', 'codes', $option{dau_color_codes}); + my $option_color_random = return_option('color', 'random', $option{dau_color_choose_colors_randomly}); + if ($option_color_random eq 'on' || $option_color_random == 1) { + $option_color_random = 1; + } else { + $option_color_random = 0; + } + + ################################################################################ + # color name -> color code + ################################################################################ + + $option_color_codes =~ s/\blight green\b/09/gi; + $option_color_codes =~ s/\bgreen\b/03/gi; + $option_color_codes =~ s/\blight red\b/04/gi; + $option_color_codes =~ s/\bred\b/05/gi; + $option_color_codes =~ s/\blight cyan\b/11/gi; + $option_color_codes =~ s/\bcyan\b/10/gi; + $option_color_codes =~ s/\blight blue\b/12/gi; + $option_color_codes =~ s/\bblue\b/02/gi; + $option_color_codes =~ s/\blight magenta\b/13/gi; + $option_color_codes =~ s/\bmagenta\b/06/gi; + $option_color_codes =~ s/\blight grey\b/15/gi; + $option_color_codes =~ s/\bgrey\b/14/gi; + + $option_color_codes =~ s/\bwhite\b/00/gi; + $option_color_codes =~ s/\bblack\b/01/gi; + $option_color_codes =~ s/\borange\b/07/gi; + $option_color_codes =~ s/\byellow\b/08/gi; + + ################################################################################ + # Produce @all_colors + ################################################################################ + + # <color code>5 shall be a colored 5 + + $option_color_codes =~ s/(\d+)/sprintf('%02d', $1)/eg; + + # Fill @all_colors and do error checking + + my @all_colors = split(/\s*;\s*/, $option_color_codes); + foreach my $code (@all_colors) { + if ($code !~ /^\d+(,\d+)?$/) { + print_err("Incorrect color code '$code'!"); + return $data; + } + } + if (@all_colors == 0) { + print_err('No color code found.'); + return $data; + } + @colors = @all_colors; + + ################################################################################ + # "-split capitals" + ################################################################################ + + if ($option_color_split eq 'capitals') { + $output = $data; + my ($color1, $color2); + if ($option_color_random) { + $color1 = $colors[rand(@colors)]; + @colors = grep { $_ ne $color1 } @colors unless (@colors == 1); + $color2 = $colors[rand(@colors)]; + } else { + if (@colors == 1) { + $color1 = $color2 = $colors[0]; + } else { + $color1 = $colors[0]; + $color2 = $colors[1]; + } + } + + $output =~ s/([[:upper:][:punct:]]+|\b\S)/\003${color1}${1}\003${color2}/g; + + # Remove needless color codes + $output =~ s/\003(?:$color1|$color2)( *)\003(?:$color1|$color2)/$1/g; + $output =~ s/\003(?:$color1|$color2)$//; + } + + ################################################################################ + # Not "-split capitals" + ################################################################################ + + else { + if ($option_color_split eq 'chars') { + $split = ''; + } elsif ($option_color_split eq 'lines') { + $split = "\n"; + } elsif ($option_color_split eq 'words') { + $split = '\s+'; + } elsif ($option_color_split eq 'rchars') { + $split = '.' x rand(10); + } elsif ($option_color_split eq 'paragraph') { + $split = "\n"; + } else { + $split = '\s+'; + } + + my $i = 0; + my $background = 0; + my $color; + for (split /($split)/, $data) { + if (/^\s*$/) { + $output .= $_; + next; + } + if ($option_color_random) { + $color = $colors[rand(@colors)]; + + $output .= "\017" if ($background && $color !~ /,/); + $output .= "\003" . $color . $_; + + if ($color =~ /,/) { + $background = 1; + } else { + $background = 0; + } + + if ($option_color_split eq 'paragraph') { + @colors = ($color); + } else { + @colors = grep { $_ ne $color } @all_colors unless (@all_colors == 1); + } + } else { + $color = $colors[($i++ % ($#colors + 1))]; + + if ($option_color_split eq 'paragraph') { + $color = $colors[0]; + } + + $output .= "\017" if ($background && $color !~ /,/); + $output .= "\003" . $color . $_; + + if ($color =~ /,/) { + $background = 1; + } else { + $background = 0; + } + } + } + } + + return $output; +} + +sub switch_cool { + my ($data, $channel) = @_; + my $output; + + ################################################################################ + # Get the options + ################################################################################ + + my $option_eol_style = return_option('cool', 'eol_style', $option{dau_cool_eol_style}); + + my $option_max = return_option('cool', 'max', $option{dau_cool_maximum_line}); + if (!defined($option_max) || int($option_max) < 0) { + $option_max = INT_MAX; + } + + my $option_prob_eol = return_option('cool', 'prob_eol', $option{dau_cool_probability_eol}); + if (!defined($option_prob_eol) || int($option_prob_eol) < 0 || int($option_prob_eol) > 100) { + $option_prob_eol = 20; + } + + my $option_prob_word = return_option('cool', 'prob_word', $option{dau_cool_probability_word}); + if (!defined($option_prob_word) || int($option_prob_word) < 0 || int($option_prob_word) > 100) { + $option_prob_word = 20; + } + + ################################################################################ + # Insert the trademarks and dollar signs + ################################################################################ + + my $max = $option_max; + foreach my $line (split /(\n)/, $data) { + foreach my $word (split /(\s)/, $line) { + if ($max > 0 && (rand(100) <= $option_prob_word) && $word =~ /^(\w+)([[:punct:]])?$/) { + $word = "${1}[tm]${2}"; + $max--; + } + if ($max > 0 && (rand(100) <= $option_prob_word) && $word =~ /^(\w+(?:\[tm\])?)([[:punct:]])?$/) { + $word = "\$${1}${2}"; + $max--; + } + $output .= $word; + } + $max = $option_max; + } + + ################################################################################ + # Reversed smileys + ################################################################################ + + my $hat = '[(<]'; + my $eyes = '[:;%]'; + my $nose = '[-]'; + my $mouth = '[)(><\[\]{}|]'; + + $output =~ s{($hat?$eyes$nose?$mouth+)}{ + # Supposed to be read from the right to the left. + # Therefore reverse all parenthesis characters: + + my $tr = $1; + $tr =~ tr/()<>[]\{\}/)(><][\}\{/; + + # Reverse the rest + + reverse($tr); + }egox; + + ################################################################################ + # EOL modifications + ################################################################################ + + my $style = $option_eol_style; + if ($option_eol_style eq 'random') { + if (int(rand(2)) && $output !~ /[?!]$/) { + $style = 'exclamation_marks'; + } else { + $style = 'suffixes'; + } + } + + # If there is no suffixes file, go for the exclamation marks + + my $file = "$option{dau_files_root_directory}/$option{dau_files_cool_suffixes}"; + unless (-e $file && -r $file && !(-z $file)) { + $style = 'exclamation_marks'; + } + + # Skip EOL modifications? + + if (int(rand(100)) > $option_prob_eol) { + $style = 'none'; + } + + # Style determined. Act accordingly: + + if ($style eq 'exclamation_marks') { + my @eol; + if ($option{dau_language} eq 'de') { + @eol = ("eins", "shifteins", "elf", "hundertelf", "tausendeinhundertundelf"); + for (1 .. 5) { + push(@eol, "eins"); + push(@eol, "elf"); + } + } else { + @eol = ("one", "shiftone", "eleven"); + for (1 .. 5) { + push(@eol, "one"); + push(@eol, "eleven"); + } + } + + $output =~ s/\s*([,.?!])*\s*$//; + $output .= '!' x (3 + int(rand(3))); + $output .= '1' x (3 + int(rand(3))); + $output .= $eol[rand(@eol)] x (1 + int(rand(1))); + $output .= $eol[rand(@eol)] x (int(rand(2))); + } elsif ($style eq 'suffixes') { + my $suffix; + if (-e $file && -r $file) { + local $/ = "\n"; + @ARGV = ($file); + srand; + rand($.) < 1 && ($suffix = switch_parse_special($_, $channel)) while <>; + } + $output =~ s/\s*$//; + + if ($output =~ /^\s*$/) { + $output = $suffix; + } else { + $output .= " " . $suffix; + } + } + + return $output; +} + +sub switch_cowsay { + my $data = shift; + my ($binarypath, $output, @cows, %cow, $cow, @cache1, @cache2); + my $skip = 1; + my $think = return_option('cowsay', 'think'); + + my $executable_name; + if ($think eq 'on') { + $binarypath = $option{dau_cowsay_cowthink_path}; + $executable_name = 'cowthink'; + } else { + $binarypath = $option{dau_cowsay_cowsay_path}; + $executable_name = 'cowsay'; + } + + if (-e $binarypath && !(-f $binarypath)) { + print_err("dau_cowsay_${executable_name}_path has to point to the $executable_name executable."); + return; + } elsif (!(-e $binarypath)) { + print_err("$executable_name not found. Install it and set dau_cowsay_${executable_name}_path."); + return; + } + + if (return_option('cowsay', 'cow')) { + $cow = return_option('cowsay', 'cow'); + } else { + while ($option{dau_cowsay_cowlist} =~ /\s*([^,\s]+)\s*,?/g) { + $cow{$1} = 1; + } + foreach my $cow (keys %{ $switches{combo}{cowsay}{cow} }) { + if (lc($option{dau_cowsay_cowpolicy}) eq 'allow') { + push(@cows, $cow) + unless ($cow{$cow}); + } elsif (lc($option{dau_cowsay_cowpolicy}) eq 'deny') { + push(@cows, $cow) + if ($cow{$cow}); + } else { + print_err('Invalid value for dau_cowsay_cowpolicy'); + return; + } + } + if (@cows == 0) { + print_err('Cannot find any cowsay cow.'); + return; + } + $cow = $cows[rand(@cows)]; + } + + # Run cowsay or cowthink + + local(*HIS_IN, *HIS_OUT, *HIS_ERR); + my @arguments; + my $option_arguments = return_option('cowsay', 'arguments'); + if ($option_arguments) { + @arguments = split(/ /, $option_arguments); + } + my $childpid = open3(*HIS_IN, *HIS_OUT, *HIS_ERR, $binarypath, '-f', $cow, @arguments); + + print HIS_IN $data or return; + close(HIS_IN) or return; + + my @errlines = <HIS_ERR>; + my @outlines = <HIS_OUT>; + close(HIS_ERR) or return; + close(HIS_OUT) or return; + + waitpid($childpid, 0); + if ($?) { + print_err("That child exited with wait status of $?"); + } + + # Error during execution? Print errors and return + + unless (@errlines == 0) { + print_err('Error during execution of cowsay'); + foreach my $line (@errlines) { + print_err($line); + } + return; + } + + if ($option{dau_cowsay_print_cow}) { + print_out("Using cowsay cow $cow"); + } + + foreach (@outlines) { + chomp; + if (/^\s*$/ && $skip) { + next; + } else { + $skip = 0; + } + push(@cache1, $_); + } + $skip = 1; + foreach (reverse @cache1) { + chomp; + if (/^\s*$/ && $skip) { + next; + } else { + $skip = 0; + } + push(@cache2, $_); + } + foreach (reverse @cache2) { + $output .= "$_\n"; + } + + return $output; +} + +sub switch_delimiter { + my $data = shift; + my $output; + my $option_delimiter_string = return_option('delimiter', 'string', $option{dau_delimiter_string}); + + foreach my $char (split //, $data) { + $output .= $char . $option_delimiter_string; + } + return $output; +} + +sub switch_dots { + my $data = shift; + + $data =~ s/[.]*\s+/ + if (rand(10) < 3) { + (rand(10) >= 5 ? ' ' : '') + . + ('...' . '.' x rand(5)) + . + (rand(10) >= 5 ? ' ' : '') + } else { ' ' } + /egox; + rand(10) >= 5 ? $data .= ' ' : 0; + $data .= ('...' . '.' x rand(10)); + + return $data; +} + +sub switch_figlet { + my $data = shift; + my $skip = 1; + my ($output, @fonts, %font, $font, @cache1, @cache2); + + if (-e $option{dau_figlet_path} && !(-f $option{dau_figlet_path})) { + print_err('dau_figlet_path has to point to the figlet executable.'); + return; + } elsif (!(-e $option{dau_figlet_path})) { + print_err('figlet not found. Install it and set dau_figlet_path.'); + return; + } + + if (return_option('figlet', 'font')) { + $font = return_option('figlet', 'font'); + } else { + while ($option{dau_figlet_fontlist} =~ /\s*([^,\s]+)\s*,?/g) { + $font{$1} = 1; + } + foreach my $font (keys %{ $switches{combo}{figlet}{font} }) { + if (lc($option{dau_figlet_fontpolicy}) eq 'allow') { + push(@fonts, $font) + unless ($font{$font}); + } elsif (lc($option{dau_figlet_fontpolicy}) eq 'deny') { + push(@fonts, $font) + if ($font{$font}); + } else { + print_err('Invalid value for dau_figlet_fontpolicy.'); + return; + } + } + if (@fonts == 0) { + print_err('Cannot find figlet fonts.'); + return; + } + $font = $fonts[rand(@fonts)]; + } + + # Run figlet + + local(*HIS_IN, *HIS_OUT, *HIS_ERR); + + my $childpid = open3(*HIS_IN, *HIS_OUT, *HIS_ERR, $option{dau_figlet_path}, '-f', $font); + + print HIS_IN $data or return; + close(HIS_IN) or return; + + my @errlines = <HIS_ERR>; + my @outlines = <HIS_OUT>; + close(HIS_ERR) or return; + close(HIS_OUT) or return; + + waitpid($childpid, 0); + if ($?) { + print_err("That child exited with wait status of $?"); + } + + # Error during execution? Print errors and return + + unless (@errlines == 0) { + print_err('Error during execution of figlet'); + foreach my $line (@errlines) { + print_err($line); + } + return; + } + + if ($option{dau_figlet_print_font}) { + print_out("Using figlet font $font"); + } + + foreach (@outlines) { + chomp; + if (/^\s*$/ && $skip) { + next; + } else { + $skip = 0; + } + push(@cache1, $_); + } + $skip = 1; + foreach (reverse @cache1) { + chomp; + if (/^\s*$/ && $skip) { + next; + } else { + $skip = 0; + } + push(@cache2, $_); + } + foreach (reverse @cache2) { + $output .= "$_\n"; + } + + return $output; +} + +sub switch_leet { + my $data = shift; + + $_ = $data; + + s'fucker'f@#$er'gi; + s/hacker/h4x0r/gi; + s/sucker/sux0r/gi; + s/fear/ph34r/gi; + + s/\b(\w+)ude\b/${1}00d/gi; + s/\b(\w+)um\b/${1}00m/gi; + s/\b(\w{3,})er\b/${1}0r/gi; + s/\bdo\b/d00/gi; + s/\bthe\b/d4/gi; + s/\byou\b/j00/gi; + + tr/lLzZeEaAsSgGtTbBqQoOiIcC/11223344556677889900||((/; + s/(\w)/rand(100) < 50 ? "\u$1" : "\l$1"/ge; + + return $_; +} + +sub switch_me { + my $data = shift; + + $command_out = 'ACTION'; + + return $data; +} + +# &switch_mix by Martin Kihlgren <zond@troja.ath.cx> +# slightly modified by myself + +sub switch_mix { + my $data = shift; + my $output; + + while ($data =~ s/(\s*)([^\w]*)([\w]+)([^\w]*)(\s+[^\w]*\w+[^\w]*\s*)*/$5/) { + my $prespace = $1; + my $prechars = $2; + my $w = $3; + my $postchars = $4; + $output = $output . $prespace . $prechars . substr($w,0,1); + my $middle = substr($w,1,length($w) - 2); + while ($middle =~ s/(.)(.*)/$2/) { + if (rand() > 0.1) { + $middle = $middle . $1; + } else { + $output = $output . $1; + } + } + if (length($w) > 1) { + $output = $output . substr($w, length($w) - 1, 1); + } + $output = $output . $postchars; + } + + return $output; +} + +sub switch_mixedcase { + my $data = shift; + + $data =~ s/([[:alpha:]])/rand(100) < 50 ? uc($1) : lc($1)/ge; + + return $data; +} + +sub switch_moron { + my ($data, $channel_rec) = @_; + my $output; + my $option_eol_style = return_option('moron', 'eol_style', $option{dau_moron_eol_style}); + my $option_language = $option{dau_language}; + + ################################################################################ + # -omega on + ################################################################################ + + my $omega; + + if (return_option('moron', 'omega') eq 'on') { + my @words = qw(omfg lol wtf); + + foreach (split / (?=\w+\b)/, $data) { + if (rand(100) < 20) { + $omega .= ' ' . $words[rand(@words)] . " $_"; + } else { + $omega .= ' ' . $_; + } + } + + $omega =~ s/\s*,\s+\@/ @/g; + $omega =~ s/^\s+//; + } + + $_ = $omega || $data; + + ################################################################################ + # 'nick: text' -> 'text @ nick' + ################################################################################ + + my $old_list_delimiter = $option{dau_parse_special_list_delimiter}; + $option{dau_parse_special_list_delimiter} = ' '; + my @nicks = split(/ /, switch_parse_special('@nicks', $channel_rec)); + $option{dau_parse_special_list_delimiter} = $old_list_delimiter; + @nicks = map { quotemeta($_) } @nicks; + + { + local $" = '|'; + eval { # Catch strange error + s/^(@nicks): (.+)/$2 @ $1/; + }; + } + + ################################################################################ + # Preparations for "EOL modifications" later + ################################################################################ + + # Remove puntuation marks at EOL and ensure there is a single space at EOL. + # This is necessary because the EOL-styles 'new' and 'classic' put them at + # EOL. If EOL-style is set to 'nothing' don't do this. + + s/\s*([,;.:?!])*\s*$// unless ($option_eol_style eq 'nothing'); + my $lastchar = $1; + + # Only whitespace? Remove it. + + s/^\s+$//; + + ################################################################################ + # Substitutions for every language + ################################################################################ + + tr/'/`/; + + # Dauify smileys + + { + # Use of uninitialized value in concatenation (.) or string at... + # (the optional dash ($1) in the regular expressions). + # Thus turn off warnings + + no warnings; + + if ($option{dau_language} eq 'de') { + if (int(rand(2))) { + s/:(-)?\)/^^/go; + } else { + s/:(-)?\)/':' . $1 . ')))' . (')' x rand(10)) . ('9' x rand(4))/ego; + } + + s/;(-)?\)/';' . $1 . ')))' . (')' x rand(10)) . ('9' x rand(4))/ego; + s/:(-)?\(/':' . $1 . '(((' . ('(' x rand(10)) . ('8' x rand(4))/ego; + s#(^|\s):(-)?/(\s|$)#$1 . ':' . $2 . '///' . ('/' x rand(10)) . ('7' x rand(4)) . $3#ego; + } else { + if (int(rand(2))) { + s/:(-)?\)/^^/go; + } else { + s/:(-)?\)/':' . $1 . ')))' . (')' x rand(10)) . ('0' x rand(4))/ego; + } + + s/;(-)?\)/';' . $1 . ')))' . (')' x rand(10)) . ('0' x rand(4))/ego; + s/:(-)?\(/':' . $1 . '(((' . ('(' x rand(10)) . ('9' x rand(4))/ego; + } + } + + ################################################################################ + # English text + ################################################################################ + + if ($option_language eq 'en') { + s/\bthe\b/teh/go; + } + + ################################################################################ + # German text + ################################################################################ + + if ($option_language eq 'de') { + + # '*GG*' -> 'ÜGGÜ' + { + my @a = ('*', 'Ü'); + my $a = $a[int(rand(@a))]; + s/\*g\*/$a . 'ggg' . ('g' x rand(10)) . $a/egio; + } + + # verbs + + s/\b(f)reuen\b/$1roien/gio; + s/\b(f)reue\b/$1roie/gio; + s/\b(f)reust\b/$1roist/gio; + s/\b(f)reut\b/$1roit/gio; + + s/\b(f)unktionieren\b/$1unzen/gio; + s/\b(f)unktioniere\b/$1unze/gio; + s/\b(f)unktionierst\b/$1unzt/gio; + s/\b(f)unktioniert\b/$1unzt/gio; + + s/\b(h)olen\b/$1ohlen/gio; + s/\b(h)ole\b/$1ohle/gio; + s/\b(h)olst\b/$1ohlst/gio; + s/\b(h)olt\b/$1ohlt/gio; + + s/\b(k)onfigurieren\b/$1 eq 'k' ? 'confen' : 'Confen'/egio; + s/\b(k)onfiguriere\b/$1 eq 'k' ? 'confe' : 'Confe'/egio; + s/\b(k)onfigurierst\b/$1 eq 'k' ? 'confst' : 'Confst'/egio; + s/\b(k)onfiguriert\b/$1 eq 'k' ? 'conft' : 'Conft'/egio; + + s/\b(l)achen\b/$1ölen/gio; + s/\b(l)ache\b/$1öle/gio; + s/\b(l)achst\b/$1ölst/gio; + s/\b(l)acht\b/$1ölt/gio; + + s/\b(m)achen\b/$1 eq 'm' ? 'tun' : 'Tun'/egio; + s/\b(m)ache\b/$1 eq 'm' ? 'tu' : 'Tu'/egio; + s/\b(m)achst\b/$1 eq 'm' ? 'tust' : 'Tust'/egio; + + s/\b(n)erven\b/$1erfen/gio; + s/\b(n)erve\b/$1erfe/gio; + s/\b(n)ervst\b/$1erfst/gio; + s/\b(n)ervt\b/$1erft/gio; + + s/\b(p)rojizieren\b/$1rojezieren/gio; + s/\b(p)rojiziere\b/$1rojeziere/gio; + s/\b(p)rojizierst\b/$1rojezierst/gio; + s/\b(p)rojiziert\b/$1rojeziert/gio; + + s/\b(r)egistrieren\b/$1egestrieren/gio; + s/\b(r)egistriere\b/$1egestriere/gio; + s/\b(r)egistrierst\b/$1egestrierst/gio; + s/\b(r)egistriert\b/$1egestriert/gio; + + s/\b(s)pazieren\b/$1patzieren/gio; + s/\b(s)paziere\b/$1patziere/gio; + s/\b(s)pazierst\b/$1patzierst/gio; + s/\b(s)paziert\b/$1patziert/gio; + + # other + + s/\bdanke\b/ + if (int(rand(2)) == 0) { + 'thx' + } else { + 'danks' + } + /ego; + s/\bDanke\b/ + if (int(rand(2)) == 0) { + 'Thx' + } else { + 'Danks' + } + /ego; + + s/\blol\b/ + if (int(rand(2)) == 0) { + 'löl' + } else { + 'löllens' + } + /ego; + s/\bLOL\b/ + if (int(rand(2)) == 0) { + 'LÖL' + } else { + 'LÖLLENS' + } + /ego; + + s/\br(?:ü|ue)ckgrat\b/ + if (int(rand(3)) == 0) { + 'rückgrad' + } elsif (int(rand(3)) == 1) { + 'rückrad' + } else { + 'rückrat' + } + /ego; + s/\bR(?:ü|ue)ckgrat\b/ + if (int(rand(3)) == 0) { + 'Rückgrad' + } elsif (int(rand(3)) == 1) { + 'Rückrad' + } else { + 'Rückrat' + } + /ego; + + s/\b(i)st er\b/$1ssa/gio; + s/\bist\b/int(rand(2)) ? 'is' : 'iss'/ego; + s/\bIst\b/int(rand(2)) ? 'Is' : 'Iss'/ego; + + s/\b(d)a(?:ss|ß) du\b/$1asu/gio; + s/\b(d)a(?:ss|ß)\b/$1as/gio; + + s/\b(s)ag mal\b/$1amma/gio; + s/\b(n)ochmal\b/$1omma/gio; + s/(m)al\b/$1a/gio; + + s/\b(u)nd nun\b/$1nnu/gio; + s/\b(n)un\b/$1u/gio; + + s/\b(s)oll denn\b/$1olln/gio; + s/\b(d)enn\b/$1en/gio; + + s/\b(s)o eine\b/$1onne/gio; + s/\b(e)ine\b/$1 eq 'e' ? 'ne' : 'Ne'/egio; + + s/\bkein problem\b/NP/gio; + s/\b(p)roblem\b/$1rob/gio; + s/\b(p)robleme\b/$1robs/gio; + + s/\b(a)ber\b/$1bba/gio; + s/\b(a)chso\b/$1xo/gio; + s/\b(a)dresse\b/$1ddresse/gio; + s/\b(a)ggressiv\b/$1gressiv/gio; + s/\b([[:alpha:]]{2,})st du\b/${1}su/gio; + s/\b(a)nf(?:ä|ae)nger\b/$1 eq 'a' ? 'n00b' : 'N00b'/egio; + s/\b(a)sozial\b/$1ssozial/gio; + s/\b(a)u(?:ss|ß)er\b/$1user/gio; + s/\b(a)utor/$1uthor/gio; + s/\b(b)asta\b/$1 eq 'b' ? 'pasta' : 'Pasta'/egio; + s/\b(b)illard\b/$1illiard/gio; + s/\b(b)i(?:ss|ß)chen\b/$1ischen/gio; + s/\b(b)ist\b/$1is/gio; + s/\b(b)itte\b/$1 eq 'b' ? 'plz' : 'Plz'/egio; + s/\b(b)lo(?:ss|ß)\b/$1los/gio; + s/\b(b)(?:ox|(?:ü|ue)chse)\b/$1yxe/gio; + s/\b(b)rillant\b/$1rilliant/gio; + s/\b(c)hannel\b/$1 eq 'c' ? 'kanal' : 'Kanal'/egio; + s/\b(c)hat\b/$1hatt/gio; + s/\b(c)ool\b/$1 eq 'c' ? 'kewl' : 'Kewl'/egio; + s/\b(d)(?:ä|ae)mlich\b/$1ähmlich/gio; + s/\b(d)etailliert\b/$1etailiert/gio; + s/\b(d)ilettantisch\b/$1illetantisch/gio; + s/\b(d)irekt\b/$1ireckt/gio; + s/\b(d)iskussion\b/$1isskusion/gio; + s/\b(d)istribution/$1ystrubution/gio; + s/\b(e)igentlich\b/$1igendlich/gio; + s/\b(e)inzige\b/$1inzigste/gio; + s/\b(e)nd/$1nt/gio; + s/\b(e)ntschuldigung\b/$1 eq 'e' ? 'sry' : 'Sry'/egio; + s/\b(f)ilm\b/$1 eq 'f' ? 'movie' : 'Movie'/egio; + s/\b(f)lachbettscanner\b/$1lachbrettscanner/gio; + s/\b(f)reu\b/$1roi/gio; + s/\b(g)alerie\b/$1allerie/gio; + s/\b(g)ay\b/$1hey/gio; + s/\b(g)ebaren\b/$1ebahren/gio; + s/\b(g)elatine\b/$1elantine/gio; + s/\b(g)eratewohl\b/$1eradewohl/gio; + s/\b(g)ibt es\b/$1ibbet/gio; + s/\bgra([dt])/$1 eq 'd' ? 'grat' : 'grad'/ego; + s/\bGra([dt])/$1 eq 'd' ? 'Grat' : 'Grad'/ego; + s/\b(h)(?:ä|ae)ltst\b/$1älst/gio; + s/\b(h)(?:ä|ae)sslich/$1äslich/gio; + s/\b(h)aneb(?:ü|ue)chen\b/$1ahneb$2chen/gio; + s/\b(i)mmobilie/$1mobilie/gio; + s/\b(i)nteressant\b/$1nterressant/gio; + s/\b(i)ntolerant\b/$1ntollerant/gio; + s/\b(i)rgend/$1rgent/gio; + s/\b(j)a\b/$1oh/gio; + s/\b(j)etzt\b/$1ez/gio; + s/\b(k)affee\b/$1affe/gio; + s/\b(k)aputt\b/$1aput/gio; + s/\b(k)arussell\b/$1arussel/gio; + s/\b(k)iste\b/$1 eq 'k' ? 'byxe' : 'Byxe'/egio; + s/\b(k)lempner\b/$1lemptner/gio; + s/\b(k)r(?:ä|ae)nker\b/$1ranker/gio; + s/\b(k)rise\b/$1riese/gio; + s/\b(l)etal\b/$1ethal/gio; + s/\b(l)eute\b/$1 eq 'l' ? 'ppl' : 'Ppl'/egio; + s/\b(l)ibyen\b/$1ybien/gio; + s/\b(l)izenz\b/$1izens/gio; + s/\b(l)oser\b/$1ooser/gio; + s/\b(l)ustig/$1ölig/gio; + s/\b(m)aschine\b/$1aschiene/gio; + s/\b(m)illennium\b/$1illenium/gio; + s/\b(m)iserabel\b/$1ieserabel/gio; + s/\b(m)it dem\b/$1im/gio; + s/\b(m)orgendlich\b/$1orgentlich/gio; + s/\b(n)(?:ä|ae)mlich\b/$1ähmlich/gio; + s/\b(n)ein\b/$1eh/gio; + s/\bnett\b/n1/gio; + s/\b(n)ewbie\b/$100b/gio; + s/\bnicht\b/int(rand(2)) ? 'net' : 'ned'/ego; + s/\bNicht\b/int(rand(2)) ? 'Net' : 'Ned'/ego; + s/\b(n)iveau/$1iwo/gio; + s/\bok(?:ay)?\b/K/gio; + s/\b(o)riginal\b/$1rginal/gio; + s/\b(p)aket\b/$1acket/gio; + s/\b(p)l(?:ö|oe)tzlich\b/$1lözlich/gio; + s/\b(p)ogrom\b/$1rogrom/gio; + s/\b(p)rogramm\b/$1roggie/gio; + s/\b(p)rogramme\b/$1roggies/gio; + s/\b(p)sychiater\b/$1sychater/gio; + s/\b(p)ubert(?:ä|ae)t\b/$1upertät/gio; + s/\b(q)uarz\b/$1uartz/gio; + s/\b(q)uery\b/$1uerry/gio; + s/\b(r)eferenz\b/$1efferenz/gio; + s/\b(r)eparatur\b/$1eperatur/gio; + s/\b(r)eply\b/$1eplay/gio; + s/\b(r)essource\b/$1esource/gio; + s/\b(r)(o)(t?fl)\b/$1 . ($2 eq 'o' ? 'ö' : 'Ö') . $3/egio; + s/\b(r)(o)(t?fl)(o)(l)\b/$1 . ($2 eq 'o' ? 'ö' : 'Ö') . $3 . ($4 eq 'o' ? 'ö' : 'Ö') . $5/egio; + s/\b(s)atellit\b/$1attelit/gio; + s/\b(s)cherz\b/$1chertz/gio; + s/\bsei([dt])\b/$1 eq 'd' ? 'seit' : 'seid'/ego; + s/\bSei([dt])\b/$1 eq 'd' ? 'Seit' : 'Seid'/ego; + s/\b(s)elig\b/$1eelig/gio; + s/\b(s)eparat\b/$1eperat/gio; + s/\b(s)eriosit(?:ä|ae)t\b/$1erösität/gio; + s/\b(s)onst\b/$1onnst/gio; + s/\b(s)orry\b/$1ry/gio; + s/\b(s)pelunke\b/$1ilunke/gio; + s/\b(s)piel\b/$1 eq 's' ? 'game' : 'Game'/egio; + s/\b(s)tabil\b/$1tabiel/gio; + s/\b(s)tandard\b/$1tandart/gio; + s/\b(s)tegreif\b/$1tehgreif/gio; + s/\b(s)ympathisch\b/$1ymphatisch/gio; + s/\b(s)yntax\b/$1ynthax/gio; + s/\b(t)era/$1erra/gio; + s/\b(t)oler/$1oller/gio; + s/\bto([td])/$1 eq 't' ? 'tod' : 'tot'/ego; + s/\bTo([td])/$1 eq 't' ? 'Tod' : 'Tot'/ego; + s/\b(u)ngef(?:ä|ae)hr\b/$1ngefär/gio; + s/\bviel gl(?:ü|ue)ck\b/GL/gio; + s/\b(v)ielleicht\b/$1ileicht/gio; + s/\b(v)oraus/$1orraus/gio; + s/\b(w)(?:ä|ae)re\b/$1ähre/gio; + s/\bwa(h)?r/$1 eq 'h' ? 'war' : 'wahr'/ego; + s/\bWa(h)?r/$1 eq 'h' ? 'War' : 'Wahr'/ego; + s/\b(w)as du\b/$1asu/gio; + s/\b(w)eil du\b/$1eilu/gio; + s/\bweis(s)?/$1 eq 's' ? 'weis' : 'weiss'/ego; + s/\bWeis(s)?/$1 eq 's' ? 'Weis' : 'Weiss'/ego; + s/\b(w)enn du\b/$1ennu/gio; + s/\b(w)ider/$1ieder/gio; + s/\b(w)ieso\b/$1iso/gio; + s/\b(z)iemlich\b/$1iehmlich/gio; + s/\b(z)umindest\b/$1umindestens/gio; + + tr/üÜ/yY/; + s/ei(?:ss?|ß)e?/ice/go; + s/eife?/ive/go; + + if(return_option('moron', 'level') >= 1) { + s/\b(u)nd\b/$1nt/gio; + s/\b(h)at\b/$1att/gio; + s/\b(n)ur\b/$1uhr/gio; + s/\b(v)er(\w+)/$1 eq 'V' ? "Fa$2" : "fa$2"/egio; + s/\b([[:alpha:]]+[b-np-tv-z])er\b/${1}a/go; + s/\b([[:alpha:]]+)ck/${1}q/go; + + s/\b([fv])(?=[[:alpha:]]{2,})/ + if (rand(10) <= 4) { + if ($1 eq 'f') { + 'v' + } + else { + 'f' + } + } else { + $1 + } + /egox; + s/\b([FV])(?=[[:alpha:]]{2,})/ + if (rand(10) <= 4) { + if ($1 eq 'F') { + 'V' + } + else { + 'F' + } + } else { + $1 + } + /egox; + s#\b([[:alpha:]]{2,})([td])\b# + my $begin = $1; + my $end = $2; + if (rand(10) <= 4) { + if ($end eq 't' && $begin !~ /t$/) { + "${begin}d" + } elsif ($end eq 'd' && $begin !~ /d$/) { + "${begin}t" + } else { + "${begin}${end}" + } + } else { + "${begin}${end}" + } + #egox; + s/\b([[:alpha:]]{2,})ie/ + if (rand(10) <= 4) { + "$1i" + } else { + "$1ie" + } + /egox; + } + } + + $data = $_; + + ################################################################################ + # Swap characters with characters near at the keyboard + ################################################################################ + + my %mark; + my %chars; + if ($option{dau_language} eq 'de') { + %chars = ( + 'a' => [ 's' ], + 'b' => [ 'v', 'n' ], + 'c' => [ 'x', 'v' ], + 'd' => [ 's', 'f' ], + 'e' => [ 'w', 'r' ], + 'f' => [ 'd', 'g' ], + 'g' => [ 'f', 'h' ], + 'h' => [ 'g', 'j' ], + 'i' => [ 'u', 'o' ], + 'j' => [ 'h', 'k' ], + 'k' => [ 'j', 'l' ], + 'l' => [ 'k', 'ö' ], + 'm' => [ 'n' ], + 'n' => [ 'b', 'm' ], + 'o' => [ 'i', 'p' ], + 'p' => [ 'o', 'ü' ], + 'q' => [ 'w' ], + 'r' => [ 'e', 't' ], + 's' => [ 'a', 'd' ], + 't' => [ 'r', 'z' ], + 'u' => [ 'z', 'i' ], + 'v' => [ 'c', 'b' ], + 'w' => [ 'q', 'e' ], + 'x' => [ 'y', 'c' ], + 'y' => [ 'x' ], + 'z' => [ 't', 'u' ], + ); + } else { + %chars = ( + 'a' => [ 's' ], + 'b' => [ 'v', 'n' ], + 'c' => [ 'x', 'v' ], + 'd' => [ 's', 'f' ], + 'e' => [ 'w', 'r' ], + 'f' => [ 'd', 'g' ], + 'g' => [ 'f', 'h' ], + 'h' => [ 'g', 'j' ], + 'i' => [ 'u', 'o' ], + 'j' => [ 'h', 'k' ], + 'k' => [ 'j', 'l' ], + 'l' => [ 'k', 'ö' ], + 'm' => [ 'n' ], + 'n' => [ 'b', 'm' ], + 'o' => [ 'i', 'p' ], + 'p' => [ 'o', 'ü' ], + 'q' => [ 'w' ], + 'r' => [ 'e', 't' ], + 's' => [ 'a', 'd' ], + 't' => [ 'r', 'z' ], + 'u' => [ 'z', 'i' ], + 'v' => [ 'c', 'b' ], + 'w' => [ 'q', 'e' ], + 'x' => [ 'y', 'c' ], + 'y' => [ 't', 'u' ], + 'z' => [ 'x' ], + ); + } + + # Do not replace one character twice + # Therefore every replace-position will be marked + + unless (lc(return_option('moron', 'typo')) eq 'off') { + for (0 .. length($data)) { + $mark{$_} = 0; + } + + for (0 .. rand(length($data))/20) { + my $pos = int(rand(length($data))); + pos $data = $pos; + unless ($mark{$pos} == 1) { + no locale; + if ($data =~ /\G([A-Za-z])/g) { + my $matched = $1; + my $replacement; + if ($matched eq lc($matched)) { + $replacement = $chars{$matched}[int(rand(@{ $chars{$matched} }))]; + } else { + $replacement = uc($chars{$matched}[int(rand(@{ $chars{$matched} }))]); + } + if ($replacement !~ /^\s*$/) { + substr($data, $pos, 1, $replacement); + $mark{$pos} = 1; + } + } + } + } + } + + ################################################################################ + # Mix in some typos (swapping characters) + ################################################################################ + + unless (lc(return_option('moron', 'typo')) eq 'off') { + foreach my $word (split /([\s\n])/, $data) { + if ((rand(100) <= 20) && length($word) > 1) { + my $position_swap = int(rand(length($word))); + if ($position_swap == 0) { + $position_swap = 1; + } elsif ($position_swap == length($word)) { + $position_swap = length($word) - 1; + } + if (substr($word, $position_swap - 1, 1) eq uc(substr($word, $position_swap - 1, 1)) && + substr($word, $position_swap, 1) eq lc(substr($word, $position_swap, 1))) + { + (substr($word, $position_swap, 1), substr($word, $position_swap - 1, 1)) = + (lc(substr($word, $position_swap - 1, 1)), uc(substr($word, $position_swap, 1))); + } else { + (substr($word, $position_swap, 1), substr($word, $position_swap - 1, 1)) = + (substr($word, $position_swap - 1, 1), substr($word, $position_swap, 1)); + } + } + $output .= $word; + } + } else { + $output = $_; + } + + ################################################################################ + # plenk + ################################################################################ + + $output =~ s/(\w+)([,;.:?!]+)(\s+|$)/ + if (rand(10) <= 8 || $3 eq '') { + "$1 $2$3" + } else { + "$1$2" + } + /egox; + + ################################################################################ + # default behaviour: uppercase text + ################################################################################ + + $output = uc($output) unless (return_option('moron', 'uppercase') eq 'off'); + + ################################################################################ + # do something at EOL + ################################################################################ + + if ($option_eol_style ne 'nothing') { + my $random = int(rand(100)); + + $output .= ' ' unless ($output =~ /^\s*$/); + + # !!!!!!??????????!!!!!!!!!!11111 + + if ($random <= 70 || $lastchar eq '!') { + my @punct = qw(? !); + $output .= $punct[rand(@punct)] x int(rand(5)) + for (1..15); + + if ($lastchar eq '?') { + $output .= '?' x (int(rand(4))+1); + } elsif ($lastchar eq '!') { + $output .= '!' x (int(rand(4))+1); + } + + if ($output =~ /\?$/) { + if ($option{dau_language} eq 'de') { + $output .= "ß" x int(rand(10)); + } else { + $output .= "/" x int(rand(10)); + } + } elsif ($output =~ /!$/) { + $output .= "1" x int(rand(10)); + } + } + + # ?¿? + + elsif ($random <= 85) { + $output .= '?¿?'; + } + + # "=\n?" + + else { + $output .= "=\n?"; + } + } + + return $output; +} + +sub switch_nothing { + my $data = shift; + + return $data; +} + +sub switch_parse_special { + my ($text, $channel) = @_; + + local $" = return_option('parse_special', 'list_delimiter', $option{dau_parse_special_list_delimiter}); + + # Build nick array with every nick in channel and + # opnick array with every op in the channel + + my @nicks = (); + my @opnicks = (); + if (defined($channel) && $channel && $channel->{type} eq 'CHANNEL') { + foreach my $nick ($channel->nicks()) { + next if ($channel->{server}->{nick} eq $nick->{nick}); + push(@nicks, $nick->{nick}); + push(@opnicks, $nick->{nick}) if ($nick->{op}); + } + } + @nicks = sort { lc($a) cmp lc($b) } @nicks; + @opnicks = sort { lc($a) cmp lc($b) } @opnicks; + + # Substitution: \n to a real newline + + $text =~ s/(?<![\\])\\n/\n/g; + + # Substitution: @nicks to all nicks of channel + + $text =~ s/(?<![\\])\@nicks/@nicks/gc; + + # Substitution: @opnicks to all nicks of channel + + $text =~ s/(?<![\\])\@opnicks/@opnicks/gc; + + # Substitution: $nick1..$nickn + + while ($text =~ /(?<![\\])\$nick(\d+)/g) { + my $substitution = $nicks[rand(@nicks)]; + $text =~ s/(?<![\\])\$nick$1([^\d]|$)/${substitution}$1/g; + @nicks = grep { $_ ne $substitution } @nicks; + last if (@nicks == 0); + } + + # Substitution: $opnick1..$opnickn + + while ($text =~ /(?<![\\])\$opnick(\d+)/g) { + my $substitution = $opnicks[rand(@opnicks)]; + $text =~ s/(?<![\\])\$opnick$1([^\d]|$)/${substitution}$1/g; + @opnicks = grep { $_ ne $substitution } @opnicks; + last if (@opnicks == 0); + } + + # Substitution: $?{ code } + + my $np; # (nested pattern) + $np = qr{ + { + (?: + (?> [^{}]+ ) # Non-capture group w/o backtracking + | + (??{ $np }) # Group with matching parens + )* + } + }x; + + while ($text =~ /(?<![\\])\$\?($np)/g) { + { + no strict; + my $replacement = eval $1; + if ($@) { + print_err('Invalid code used in construct $?{ code }. Details:'); + print_err($@); + return; + } else { + chomp($replacement); + $text =~ s/(?<![\\])\$\?($np)/$replacement/; + } + } + } + + # Substitution: irssi's special variables + + if ((defined($channel) && $channel && + ($channel->{type} eq 'CHANNEL' || $channel->{type} eq 'QUERY')) && + !(lc(return_option('parse_special', 'irssi_variables')) eq 'off')) + { + $text = $channel->parse_special($text); + } + + return $text; +} + +sub switch_reverse { + my $data = shift; + + $data = reverse($data); + + return $data; +} + +sub switch_stutter { + my $data = shift; + my $output; + my @words = qw(eeeh oeeeh aeeeh); + + foreach (split / (?=\w+\b)/, $data) { + if (rand(100) < 20) { + $output .= ' ' . $words[rand(@words)] . ", $_"; + } else { + $output .= ' ' . $_; + } + } + + $output =~ s/\s*,\s+\@/ @/g; + + for (1 .. rand(length($output)/5)) { + pos $output = rand(length($output)); + $output =~ s/\G ([[:alpha:]]+)\b/ $1, $1/; + } + for (1 .. rand(length($output)/10)) { + pos $output = rand(length($output)); + $output =~ s/\G([[:alpha:]])/$1 . ($1 x rand(3))/e; + } + + $output =~ s/^\s+//; + + return $output; +} + +sub switch_substitute { + $_ = shift; + + my $file = "$option{dau_files_root_directory}/$option{dau_files_substitute}"; + + if (-e $file && -r $file) { + my $return = do $file; + + if ($@) { + print_err("parsing $file failed: $@"); + } + unless (defined($return)) { + print_err("'do $file' failed"); + } + } + + return $_; +} + +sub switch_underline { + my $data = shift; + + $data = "\037$data\037"; + + return $data; +} + +sub switch_uppercase { + my $data = shift; + + $data = uc($data); + + return $data; +} + +sub switch_words { + my $data = shift; + my $output; + my @numbers; + + if ($option{dau_words_range} =~ /^([1-9])-([1-9])$/) { + my $x = $1; + my $y = $2; + unless ($x <= $y) { + print_err('Invalid value for setting dau_words_range.'); + return; + } + if ($x == $y) { + push(@numbers, $x); + } elsif ($x < $y) { + for (my $i = $x; $i <= $y; $i++) { + push(@numbers, $i); + } + } + } else { + print_err('Invalid value for dau_words_range.'); + return; + } + my $random = $numbers[rand(@numbers)]; + while ($data =~ /((?:.*?(?:\s+|$)){1,$random})/g) { + $output .= "$1\n" + unless (length($1) == 0); + $random = $numbers[rand(@numbers)]; + } + + $output =~ s/\s*$//; + + return $output; +} + +################################################################################ +# Subroutines (signals) +################################################################################ + +sub signal_channel_destroyed { + my ($channel) = @_; + + my $channel_name = $channel->{name}; + my $network_name = $channel->{server}->{tag}; + + $daumode{channels_in}{$network_name}{$channel_name} = 0; + $daumode{channels_out}{$network_name}{$channel_name} = 0; + $daumode{channels_in_modes}{$network_name}{$channel_name} = ''; + $daumode{channels_out_modes}{$network_name}{$channel_name} = ''; +} + +sub signal_channel_joined { + my ($channel) = @_; + + # Resume babbles + + if (defined($babble{timer_writing})) { + if ($babble{channel}->{name} eq $channel->{name} && + $babble{channel}->{server}->{tag} eq $channel->{server}->{tag}) + { + $channel->print('%9dau.pl:%9 Continuing babble...'); + timer_babble_writing(); + } + } + + # Automatically set daumode + + daumode_channels(); +} + +sub signal_command_msg { + my ($args, $server, $witem) = @_; + + $args =~ /^(?:-\S+\s)?(?:\S*)\s(.*)/; + my $data = $1; + + $command_in .= "$data\n"; + + Irssi::signal_stop(); +} + +sub signal_complete_word { + my ($list, $window, $word, $linestart, $want_space) = @_; + + # Parsing the commandline for dau.pl is relatively complicated. + # TAB completion depends on commandline parsing in dau.pl. + # Script autors looking for a simple example for irssi's + # TAB completion are wrong here. + + my $server = Irssi::active_server(); + my $channel = $window->{active}; + my @switches_combo = map { $_ = "--$_" } keys %{ $switches{combo} }; + my @switches_nocombo = map { $_ = "--$_" } keys %{ $switches{nocombo} }; + my @nicks = (); + + # Only complete when the commandline starts with '${k}dau'. + # If not, let irssi do the work + + return unless ($linestart =~ /^\Q${k}\Edau/i); + + # Remove everything syntactically correct thing of $linestart. + # If there is anything else but whitespace at the end of + # commandline parsing, we have an syntax error. + # If we have a syntax error, complete only nicks. + + $linestart =~ s/^\Q${k}\Edau ?//i; + + # Generate list of nicks in current channel for later use + + if (defined($channel->{type}) && $channel->{type} eq 'CHANNEL') { + foreach my $nick ($channel->nicks()) { + if ($nick->{nick} =~ /^\Q$word\E/i && + $window->{active_server}->{nick} ne $nick->{nick}) + { + push(@nicks, $nick->{nick}); + } + } + } + + # Variables + + my $combo = 0; # Boolean: True if last switch was one of keys %{ $switches{combo} } + my $syntax_error = 0; # Boolean: True if syntax error found + my $counter = 0; # Integer: Counts first level options + my $first_level_option = ''; # String: Last first level option + my $second_level_option = ''; # String: Last second level option + my $third_level_option = 0; # Boolean: True if found a third level option + + # Parsing commandline now. Set variables accordingly. + + OUTER: while ($linestart =~ /^--(\w+) ?/g) { + + $second_level_option = ''; + $third_level_option = 0; + + # Found a first level option (combo) + + if (ref($switches{combo}{$1}{'sub'})) { + $first_level_option = $1; + $combo = 1; + } + + # Found a first level option (nocombo) + + elsif (ref($switches{nocombo}{$1}{'sub'}) && $counter == 0) { + $first_level_option = $1; + $combo = 0; + } + + # Not a first level option => Syntax error + + else { + $syntax_error = 1; + last OUTER; + } + + # Syntactically correct => remove it + + $linestart =~ s/^--\w+ ?//; + + # Checkout if there are Second- or third level options + + INNER: while ($linestart =~ /^-(\w+)(?: ('.*?(?<![\\])'|\S+))? ?/g) { + + my $second_level = $1; + my $third_level = $2 || ''; + + $third_level =~ s/^'//; + $third_level =~ s/'$//; + $third_level =~ s/\\'/'/g; + + # Do the same for combo and nocombo-options. They have to be + # handled separately anyway. + + # combo... + + if ($combo) { + + # Found a second level option + + if ($switches{combo}{$first_level_option}{$second_level}) { + $second_level_option = $second_level; + } + + # Not a second level option => Syntax error + + else { + $syntax_error = 1; + last OUTER; + } + + # Syntactically correct => remove it + + $linestart =~ s/^-\w+//; + + # Found something in the regexp of the INNER-while-loop-condition, + # which is perhaps a third level option + + if ($third_level) { + + # Found a third level option + + if ($switches{combo}{$first_level_option}{$second_level_option}{$third_level} || + $switches{combo}{$first_level_option}{$second_level_option}{'*'}) + { + $third_level_option = 1; + + # Syntactically correct => remove it + + $linestart =~ s/^(?: ('.*?(?<![\\])'|\S+))? ?//; + } + + # Not a third level option => Syntax error + + else { + $syntax_error = 1; + last OUTER; + } + + # Nothing found which comes into question for a third level option. + # The commandline has to be empty now (remember: everything + # syntactically correct has been removed) or we have a syntax error. + + } else { + + # Empty! Later we will complete to third level options + + if ($linestart =~ /^\s*$/) { + $third_level_option = 0; + } + + # Not empty => Syntax error + + else { + $syntax_error = 1; + last OUTER; + } + } + + # nocombo... + + } else { + + # Found a second level option + + if ($switches{nocombo}{$first_level_option}{$second_level}) { + $second_level_option = $second_level; + } + + # Not a second level option => Syntax error + + else { + $syntax_error = 1; + last OUTER; + } + + # Syntactically correct => remove it + + $linestart =~ s/^-\w+//; + + # Found something in the regexp of the INNER while loop condition, + # which is perhaps a third level option + + if ($third_level) { + + # Found a third level option + + if ($switches{nocombo}{$first_level_option}{$second_level_option}{$third_level} || + $switches{nocombo}{$first_level_option}{$second_level_option}{'*'}) + { + $third_level_option = 1; + + # Syntactically correct => remove it + + $linestart =~ s/^(?: ('.*?(?<![\\])'|\S+))? ?//; + } + + # Not a third level option => Syntax error + + else { + $syntax_error = 1; + last OUTER; + } + + # Nothing found which comes into question for a third level option. + # The commandline has to be empty now (remember: everything + # syntactically correct has been removed) or we have a syntax error. + + } else { + + # Empty! Later we will complete to third level options + + if ($linestart =~ /^\s*$/) { + $third_level_option = 0; + } + + # Not empty => Syntax error + + else { + $syntax_error = 1; + last OUTER; + } + } + } + } + } continue { + $counter++; + } + + # End of commandline-parsing. + # Everything syntactically correct removed. + # If commandline is not empty now, we have a syntax error. + + if ($linestart !~ /^\s*$/) { + $syntax_error = 1; + } + + # Do the TAB completion + + @$list = (); + + if ($syntax_error) { + foreach my $x (sort @nicks) { + if($x =~ /^$word/i) { + push(@$list, $x); + } + } + } + elsif ($counter == 0) { + foreach my $x ((sort(@switches_combo, @switches_nocombo), sort(@nicks))) { + if($x =~ /^$word/i) { + push(@$list, $x); + } + } + } + elsif (($combo && $first_level_option && $second_level_option && $third_level_option) || + ($combo && $first_level_option && !$second_level_option && !$third_level_option)) + { + my @switches_second_level = grep !/^-sub$/, map { $_ = "-$_" } + keys %{ $switches{combo}{$first_level_option} }; + + foreach my $x ((sort(@switches_second_level), sort(@switches_combo), sort(@nicks))) { + if($x =~ /^$word/i) { + push(@$list, $x); + } + } + } + elsif ((!$combo && $counter == 1 && $first_level_option && $second_level_option && $third_level_option) || + (!$combo && $counter == 1 && $first_level_option && !$second_level_option && !$third_level_option)) + { + my @switches_second_level = grep !/^-sub$/, map { $_ = "-$_" } + keys %{ $switches{nocombo}{$first_level_option} }; + + foreach my $x (sort(@switches_second_level)) { + if($x =~ /^$word/i) { + push(@$list, $x); + } + } + } + elsif ($combo && $first_level_option && $second_level_option && !$third_level_option) { + my @switches_third_level = grep !/^\*$/, + keys %{ $switches{combo}{$first_level_option}{$second_level_option} }; + + foreach my $x (sort(@switches_third_level)) { + if($x =~ /^$word/i) { + push(@$list, $x); + } + } + } + elsif (!$combo && $counter == 1 && $first_level_option && $second_level_option && !$third_level_option) { + my @switches_third_level = grep !/^\*$/, + keys %{ $switches{nocombo}{$first_level_option}{$second_level_option} }; + + foreach my $x ((sort(@switches_third_level), sort(@nicks))) { + if($x =~ /^$word/i) { + push(@$list, $x); + } + } + } + + Irssi::signal_stop(); +} + +sub signal_event_404 { + my ($server, $message, $network_name) = @_; + + if ($message =~ /^(?:\S+) (\S+) :Cannot send to channel$/) { + my $channel_name = $1; + + if ($server->{tag} eq $babble{channel}->{server}->{tag} && + $babble{channel}->{name} eq $channel_name && + defined($babble{timer_writing})) + { + Irssi::timeout_remove($babble{timer_writing}); + undef($babble{timer_writing}); + print_out("%9dau.pl:%9 Could not send message to $babble{channel}->{name}/$babble{channel}->{server}->{tag}. Cancelling babble."); + return; + } + } + + if ($message =~ /^(?:\S+) (\S+) :(.*)/) { + Irssi::print("$1 $2"); + } else { + Irssi::print($message); + } +} + +sub signal_event_privmsg { + my ($server, $data, $nick, $hostmask) = @_; + my ($channel_name, $text) = split / :/, $data, 2; + my $channel_rec = $server->channel_find($channel_name); + $channel_name = lc($channel_name); + my $server_name = lc($server->{tag}); + my %lookup; + + while ($option{dau_remote_channellist} =~ /\s*([^\/]+)\/([^,]+)\s*,?/g) { + my $channel = $1; + $channel = lc($channel); + my $ircnet = $2; + $ircnet = lc($ircnet); + $lookup{$ircnet}{$channel} = 1; + } + if (lc($option{dau_remote_channelpolicy}) eq 'allow') { + return if ($lookup{$server_name}{$channel_name}); + } elsif (lc($option{dau_remote_channelpolicy}) eq 'deny') { + return unless ($lookup{$server_name}{$channel_name}); + } else { + return; + } + + # Remove formatting so dau.pl can reply to a colored, underlined, ... + # question + + $text =~ s/\003\d?\d?(?:,\d?\d?)?|\002|\006|\007|\016|\01f|\037//g; + + my $regexp = switch_parse_special($option{dau_remote_question_regexp}, $channel_rec); + if ($text =~ /$regexp/) { + my $reply = return_random_list_item($option{dau_remote_question_reply}); + $reply =~ s/(?<![\\])\$nick/$nick/g; + $reply = parse_text($reply, $channel_rec); + + output_text($server, $channel_name, $reply); + } +} + +sub signal_nick_mode_changed { + my ($channel, $nick, $setby, $mode, $type) = @_; + my ($reply, %lookup); + my $channel_name = lc($channel->{name}); + my $network_name = lc($channel->{server}->{tag}); + my $op = $nick_mode{$network_name}{$channel_name}{op}; # mode before nick change + my $voice = $nick_mode{$network_name}{$channel_name}{voice}; # mode before nick change + + return if ($channel->{server}->{nick} ne $nick->{nick}); + if ($nick->{nick} eq $setby || $setby eq 'irc.psychoid.net') { + build_nick_mode_struct(); + return; + } + + # Only act in channels where the user wants dau.pl to act + + while ($option{dau_remote_channellist} =~ /\s*([^\/]+)\/([^,]+)\s*,?/g) { + my $channel = $1; + $channel = lc($channel); + my $ircnet = $2; + $ircnet = lc($ircnet); + $lookup{$ircnet}{$channel} = 1; + } + if (lc($option{dau_remote_channelpolicy}) eq 'allow') { + if ($lookup{$network_name}{$channel_name}) { + build_nick_mode_struct(); + return; + } + } elsif (lc($option{dau_remote_channelpolicy}) eq 'deny') { + unless ($lookup{$network_name}{$channel_name}) { + build_nick_mode_struct(); + return; + } + } else { + build_nick_mode_struct(); + return; + } + + # Now we are in the right channel + + if ($option{dau_remote_permissions} =~ /^[01]1[01][01][01][01]$/) { + if ($mode eq '+' && $type eq '+' && (!$voice && !$op)) { + $reply = return_random_list_item($option{dau_remote_voice_reply}); + $reply =~ s/(?<![\\])\$nick/$setby/g; + $reply = parse_text($reply, $channel); + } + } + if ($option{dau_remote_permissions} =~ /^[01][01]1[01][01][01]$/) { + if ($mode eq '@' && $type eq '+' && !$op) { + $reply = return_random_list_item($option{dau_remote_op_reply}); + $reply =~ s/(?<![\\])\$nick/$setby/g; + $reply = parse_text($reply, $channel); + } + } + if ($option{dau_remote_permissions} =~ /^[01][01][01]1[01][01]$/) { + if ($mode eq '+' && $type eq '-' && ($voice && !$op)) { + $reply = return_random_list_item($option{dau_remote_devoice_reply}); + $reply =~ s/(?<![\\])\$nick/$setby/g; + $reply = parse_text($reply, $channel); + } + } + if ($option{dau_remote_permissions} =~ /^[01][01][01][01]1[01]$/) { + if ($mode eq '@' && $type eq '-' && $op) { + $reply = return_random_list_item($option{dau_remote_deop_reply}); + $reply =~ s/(?<![\\])\$nick/$setby/g; + $reply = parse_text($reply, $channel); + } + } + + # rebuild nick mode struct and print out the reply + + build_nick_mode_struct(); + output_text($channel, $channel->{name}, $reply); +} + +sub signal_send_text { + my ($data, $server, $witem) = @_; + my $output; + + return unless (defined($server) && $server && $server->{connected}); + return unless (defined($witem) && $witem && + ($witem->{type} eq 'CHANNEL' || $witem->{type} eq 'QUERY')); + + if ($daumode{channels_out}{$server->{tag}}{$witem->{name}} == 1) { + if ($daumode{channels_out_modes}{$server->{tag}}{$witem->{name}} eq '') { + $output = parse_text($daumode{channels_out_modes}{$server->{tag}}{$witem->{name}} . $data, $witem); + } else { + $output = parse_text($daumode{channels_out_modes}{$server->{tag}}{$witem->{name}} . ' ' . $data, $witem); + } + + output_text($witem, $witem->{name}, $output); + + Irssi::signal_stop(); + } +} + +sub signal_setup_changed { + set_settings(); + + # setting changed/added => change/add it here + + # setting cmdchars + + $k = Irssi::parse_special('$k'); + + # babble history + + if (defined($babble{history}) && ref($babble{history}) eq 'ARRAY') { + my @history; + my $i = 1; + foreach (@{ $babble{history} } ) { + if ($i++ <= $option{dau_babble_history_size}) { + push(@history, $_); + } + } + @{ $babble{history} } = @history; + } + + # setting dau_cowsay_cowpath + + cowsay_cowlist($option{dau_cowsay_cowpath}); + + # setting dau_figlet_fontpath + + figlet_fontlist($option{dau_figlet_fontpath}); + + # setting dau_daumode_channels + + daumode_channels(); + + # setting dau_statusbar_daumode_hide_when_off + + Irssi::statusbar_items_redraw('daumode'); + + # timer for the babble feature + + timer_remote_babble_reset(); + + # signal handling + + signal_handling(); +} + +sub signals_daumode_in { + my ($server, $data, $nick, $hostmask, $target) = @_; + my $channel_rec = $server->channel_find($target); + my $i_channel = $daumode{channels_in}{$server->{tag}}{$target}; + my $i_modes = $daumode{channels_in_modes}{$server->{tag}}{$target}; + my $modified_msg; + + return unless (defined($server) && $server && $server->{connected}); + + # Not one of the channels where daumode for incoming messages is turned on. + # In those channels print out the message as it is and leave the subroutine + + if (!$i_channel) { + return; + } + + # Evil Hack? + # I had to dauify every incoming messages. Using &signal_continue was + # not possible because --words f.e. generates output over multiple lines. So I + # had to create multiple messages using &signal_emit. Those just created + # messages shouldn't be dauified again when entering this subroutine. I + # couldn't prevent irssi from entering this subroutine again after + # dauifying the text so the messages had to be 'marked'. Marked + # messages will not be dauified again. I think \x02 at the beginning of the + # message is ok for that. + + if ($data =~ s/^\x02//) { + Irssi::signal_continue($server, $data, $nick, $hostmask, $target); + } else { + if ($i_modes ne '') { + $modified_msg = parse_text($i_modes . ' ' . $data, $channel_rec); + } else { + $modified_msg = parse_text($data, $channel_rec); + } + + if ($modified_msg =~ /\n/) { + for my $line (split /\n/, $modified_msg) { + Irssi::signal_emit(Irssi::signal_get_emitted(), $server, "\x02$line", $nick, $hostmask, $target); + Irssi::signal_stop(); + } + } else { + Irssi::signal_emit(Irssi::signal_get_emitted(), $server, "\x02$modified_msg", $nick, $hostmask, $target); + Irssi::signal_stop(); + } + } +} + +################################################################################ +# Subroutines (statusbar) +################################################################################ + +sub statusbar_daumode { + my ($item, $get_size_only) = @_; + my ($status_in, $status_out, $modes_in, $modes_out); + my $server = Irssi::active_server(); + my $witem = Irssi::active_win()->{active}; + my $theme = Irssi::current_theme(); + my $format = $theme->format_expand('{sb_daumode}'); + + if ($witem && ref($witem) && + $server && ref($server) && + ($witem->{type} eq 'CHANNEL' || $witem->{type} eq 'QUERY')) + { + if (defined($daumode{channels_in}{$server->{tag}}{$witem->{name}}) && + $daumode{channels_in}{$server->{tag}}{$witem->{name}} == 1) + { + $status_in = 'ON'; + } else { + $status_in = 'OFF'; + } + + if (defined($daumode{channels_out}{$server->{tag}}{$witem->{name}}) && + $daumode{channels_out}{$server->{tag}}{$witem->{name}} == 1) + { + $status_out = 'ON'; + } else { + $status_out = 'OFF'; + } + + # Hide statusbaritem if setting dau_statusbar_daumode_hide_when_off + # is turned on and daumode is turned off + + if ($status_in eq 'OFF' && $status_out eq 'OFF' && $option{dau_statusbar_daumode_hide_when_off}) { + $item->{min_size} = $item->{max_size} = 0; + return; + } + + if ($status_in eq 'ON') { + $modes_in = $daumode{channels_in_modes}{$server->{tag}}{$witem->{name}} || $option{dau_standard_options}; + } else { + $modes_in = ''; + } + if ($status_out eq 'ON') { + $modes_out = $daumode{channels_out_modes}{$server->{tag}}{$witem->{name}} || $option{dau_standard_options}; + } else { + $modes_out = ''; + } + + if ($format) { + $format = $theme->format_expand("{sb_daumode $status_out $modes_out $status_in $modes_in}"); + } else { + if ($status_in eq 'OFF' && $status_out eq 'OFF') { + $format = $theme->format_expand("{sb daumode: <- $status_in | -> $status_out}"); + } + elsif ($status_in eq 'OFF' && $status_out eq 'ON') { + $format = $theme->format_expand("{sb daumode: <- $status_in | -> $status_out ($modes_out)}"); + } + elsif ($status_in eq 'ON' && $status_out eq 'OFF') { + $format = $theme->format_expand("{sb daumode: <- $status_in ($modes_in) | -> $status_out}"); + } + elsif ($status_in eq 'ON' && $status_out eq 'ON') { + $format = $theme->format_expand("{sb daumode: <- $status_in ($modes_in) | -> $status_out ($modes_out)}"); + } + } + } else { + $item->{min_size} = $item->{max_size} = 0; + return; + } + + $item->default_handler($get_size_only, $format, '', 1); +} + +################################################################################ +# Subroutines (timer) +################################################################################ + +# for the babble remote feature + +sub timer_away_reminder { + my $id = shift; + $id =~ m{^([^/]+)/(.+)}; + my $channel = $1; + my $network = $2; + + my $server_rec = Irssi::server_find_tag($network); + + unless (defined($server_rec) && $server_rec) { + return; + } + + my $channel_rec = $server_rec->channel_find($channel); + + unless (defined($channel_rec) && $channel_rec && + ($channel_rec->{type} eq 'CHANNEL' || $channel_rec->{type} eq 'QUERY')) + { + return; + } + + ################################################################################ + # Open file + ################################################################################ + + my $file = "$option{dau_files_root_directory}/$option{dau_files_away}"; + my @file; + unless (tie(@file, 'Tie::File', $file)) { + print_err("Cannot tie $file!"); + return; + } + + ################################################################################ + # Go through file + ################################################################################ + + # Format: + # channel | network | time | options | reminder | interval | reason + + my ($time, $options, $reminder, $interval, $reason); + foreach my $line (@file) { + if ($line =~ m{^$channel\x02$network\x02(\d+)\x02([^\x02]*)\x02(\d)\x02(\d+)\x02(.*)}) { + $time = $1; + $options = $2; + $reminder = $3; + $interval = $4; + $reason = $5; + last; + } + } + + ################################################################################ + # Special variables + ################################################################################ + + my $output = $option{dau_away_reminder_text}; + + # $time + + my $difference = time_diff_verbose(time, $time); + $output =~ s/\$time/$difference/g; + + # $reason + + if ($option{dau_away_quote_reason}) { + $reason =~ s/\\/\\\\/g; + $reason =~ s/\$/\\\$/g; + } + $output =~ s/\$reason/$reason/g; + + ################################################################################ + # Write text to channels. Write changes back to file + ################################################################################ + + untie(@file); + + $output = parse_text("$options $output", $channel_rec); + + output_text($channel_rec, $channel_rec->{name}, $output); +} + +# all babbles: the writing to the channel + +sub timer_babble_writing { + + # check if we are still on the channel + + my $onChannel = 0; + foreach my $server (Irssi::servers()) { + if ($server->{tag} eq $babble{channel}->{server}->{tag}) { + foreach my $channel ($server->channels()) { + if ($babble{channel}->{name} eq $channel->{name}) { + if ($babble{channel} != $channel) { + $babble{channel} = $channel; + } + $onChannel = 1; + } + } + } + } + if (!$onChannel) { + Irssi::timeout_remove($babble{timer_writing}); + print_out("%9dau.pl:%9 You are not on $babble{channel}->{name}/$babble{channel}->{server}->{tag}. Stalling babble."); + return; + } + + # restore the variables + + $command_out = $babble{command_out_history}{$babble{counter}}; + $command_out_activated = $babble{command_out_history_switch}{$babble{counter}}; + + # then output text + + output_text($babble{channel}, $babble{channel}->{name}, $babble{line}); + + # And go to the "managing" subroutine... + + timer_babble_writing_reset(); +} + +# all babbles: the timer for the next writing + +sub timer_babble_writing_reset { + my $interval = 0; + + # Remove used writing timer, if existent (at the first run we don't have any timer) + + Irssi::timeout_remove($babble{timer_writing}) if (defined($babble{timer_writing})); + + # At each run of this managing subroutine remove one line of text + + $babble{text} =~ s/^(.*?)\n//; + $babble{line} = $1; + + if ($babble{line} =~ s/^BABBLE_INTERVAL=(\d+)\x02//) { + $interval = $1; + $babble{line} = parse_text("$option{dau_babble_options_line_by_line} $babble{line}"); + my $counter = $babble{counter} + 1; + $babble{command_out_history}{$counter} = $command_out; + $babble{command_out_history_switch}{$counter} = $command_out_activated; + } + + # If there is still some text left, add a new timer for the next line + + if (length($babble{text}) != 0 || length($babble{line}) != 0) { + + if ($babble{counter}++ == 0) { + if ($option{dau_babble_verbose} && $babble{numberoflines} >= $option{dau_babble_verbose_minimum_lines}) { + $babble{channel}->print("%9dau.pl:%9 Babbling $babble{numberoflines} line" . ($babble{numberoflines} > 1 ? 's' : '') . ' now:'); + } + $interval = 50; + } + + if ($interval < 10) { + # Calculate the writing breaks + # The longer the next line is the longer the break will be + + $interval = 1000 + rand(2000) + + 50 * length($babble{line}) + + rand(25 * length($babble{line})); + + # Some characters need more time to write + + while ($babble{line} =~ /[^a-z ]/gio) { + $interval += (75 + rand(25)); + } + + $interval = int($interval); + } + + # Set timer + + $babble{timer_writing} = Irssi::timeout_add($interval, \&timer_babble_writing, ''); + } + + # No text left? + + else { + if ($option{dau_babble_verbose} && $babble{numberoflines} >= $option{dau_babble_verbose_minimum_lines}) { + $babble{channel}->print('%9dau.pl:%9 Finished babbling.'); + } + + # remove the timer + + undef($babble{timer_writing}); + + if ($babble{remote}) { + timer_remote_babble_reset(); + } + } +} + +# remote babble: initialize + +sub timer_remote_babble { + my $text; + + # Push all channels where it's ok to babble text in @channels + + my %lookup; + while ($option{dau_remote_babble_channellist} =~ /\s*([^\/]+)\/([^,]+)\s*,?/g) { + my $channel = $1; + $channel = lc($channel); + my $ircnet = $2; + $ircnet = lc($ircnet); + $lookup{$ircnet}{$channel} = 1; + } + + my @channels; + foreach my $server (Irssi::servers()) { + my $server_name = lc($server->{tag}); + + foreach my $channel ($server->channels()) { + my $channel_name = lc($channel->{name}); + + if (lc($option{dau_remote_babble_channelpolicy}) eq 'allow' && + !$lookup{$server_name}{$channel_name}) + { + push(@channels, $channel); + } + elsif (lc($option{dau_remote_babble_channelpolicy}) eq 'deny' && + $lookup{$server_name}{$channel_name}) + { + push(@channels, $channel); + } + } + } + + # No channels found => return + + return if (@channels == 0); + + # Choose one of the @channels + + my $channel = $channels[rand(@channels)]; + + # If something is babbling right now, stop + + if (defined($babble{timer_writing})) { + return; + } + + # else get text from file + + else { + my @filter = (); + $text = &babble_get_text($channel, \@filter, undef, $option{dau_babble_history_size}); + } + + # Stop the timer for the big breaks. + + Irssi::timeout_remove($babble{timer_remote}) if (defined($babble{timer_remote})); + + # Start the writing. + + babble_start($channel, $text, 1); +} + +# remote babble: reset + +sub timer_remote_babble_reset { + Irssi::timeout_remove($babble{timer_remote}) if (defined($babble{timer_remote})); + + # Do not set the timer, if the permission-bit is not set + + return unless ($option{dau_remote_permissions} =~ /^[01][01][01][01][01]1$/); + + # Calculate interval + + my $interval = babble_set_interval($option{dau_remote_babble_interval}, $option{dau_remote_babble_interval_accuracy}); + + # Set timer + + if ($interval != 0) { + $babble{timer_remote} = Irssi::timeout_add($interval, \&timer_remote_babble, ''); + } +} + +################################################################################ +# Helper subroutines +################################################################################ + +sub babble_get_text { + my ($channel, $filter, $nicks, $history_size) = @_; + my $output; + + # Return a random line from the dau_files_babble_messages file + + my ($text, @file, @filterindex); + my $file = "$option{dau_files_root_directory}/$option{dau_files_babble_messages}"; + + if (-e $file && -r $file) { + unless (tie(@file, 'Tie::File', $file)) { + print_err("Cannot tie $file!"); + return; + } + } else { + print_err("Couldn't access babble file '$file'!"); + return; + } + + my @nicks_channel = (); + my @opnicks_channel = (); + if (defined($channel) && $channel && $channel->{type} eq 'CHANNEL') { + foreach my $nick ($channel->nicks()) { + next if ($channel->{server}->{nick} eq $nick->{nick}); + push(@nicks_channel, $nick->{nick}); + push(@opnicks_channel, $nick->{nick}) if ($nick->{op}); + } + } + + my @compiled_patterns_filter; + eval { # possible user input here + @compiled_patterns_filter = map { qr/$_/i } @$filter; + }; + if ($@) { + print_err("The %9-filter%9 you gave wasn't a valid regular expression."); + print_err($@); + return; + } + my $compiled_pattern_nicks = qr/(?<![\\])\$nick(\d+)/; + my $compiled_pattern_ops = qr/(?<![\\])\$opnick(\d+)/; + + my $i = 0; + foreach my $line (@file) { + my $add = 1; + + # Every filter has to match + + FILTER: foreach my $filter (@compiled_patterns_filter) { + if ($line !~ /$filter/) { + $add = 0; + last FILTER; + } + } + + # Check against history + + if ($add) { + my $i = 1; + foreach (@{ $babble{history} }) { + if ($i++ <= $history_size) { + if ($line eq $_) { + $add = 0; + } + } + } + } + + # Don't babble at non-existent nicks + + if ($add) { + my $minimum_number_nicks = 0; + while ($line =~ /$compiled_pattern_nicks/g) { + if ($1 > $minimum_number_nicks) { + $minimum_number_nicks = $1; + } + } + if (defined($nicks) && @$nicks > 0) { + if (scalar(@$nicks) < $minimum_number_nicks) { + $add = 0; + } + } else { + if (scalar(@nicks_channel) < $minimum_number_nicks) { + $add = 0; + } + } + } + + # Don't babble at non-existent channel operators + + if ($add) { + if ($line =~ /$compiled_pattern_ops/) { + my $minimum_number_ops = 0; + while ($line =~ /$compiled_pattern_ops/g) { + if ($1 > $minimum_number_ops) { + $minimum_number_ops = $1; + } + } + if (defined($nicks) && @$nicks > 0) { + if (scalar(@$nicks) < $minimum_number_ops) { + $add = 0; + } + } else { + if (scalar(@opnicks_channel) < $minimum_number_ops) { + $add = 0; + } + } + } + } + + # Add the line as it passed all the tests + + if ($add) { + push(@filterindex, $i); + } + $i++; + } + $text = $file[$filterindex[int(rand(@filterindex))]]; + + if (@filterindex == 0) { + print_err("Babble failed. Possible reasons: a) Too restrictive %9-filter%9 in place b) No matching lines in the babble file c) babble history holding that babble d) Not enough people in the channel"); + return; + } + + if (!$text) { + print_err("No text to babble."); + return; + } + + # Put babble in global history and shorten it, if necessary + + @{ $babble{history} } = ($text, @{ $babble{history} }); + if (scalar(@{ $babble{history} }) > $option{dau_babble_history_size}) { + pop(@{ $babble{history} }); + } + + # dauify $text and return the dauified $output + + my $options = $option{dau_babble_options_line_by_line}; + + # We have to keep track of the command history. --me and the --command + # switch change the variables $command_out and $command_out_activated. + # Because they are reset after every run of parse_text() they have to be kept + # in a struct so that the writing timers later can do their job correctly. + + my $counter = 1; + $babble{command_out_history} = (); + $babble{command_out_history_switch} = (); + + # parse for special characters and substitute them + + if (defined($nicks)) { + if (@$nicks > 0) { + for (my $i = 1; $i <= @$nicks; $i++) { + $text =~ s/(?<![\\])\$nick$i/@$nicks[$i - 1]/g; + } + } + $text = switch_parse_special($text, $channel); + } else { + $text = switch_parse_special($text, $channel); + } + + # Preprocessing options + + if ($option{dau_babble_options_preprocessing} !~ /^\s*$/) { + $text = parse_text("$option{dau_babble_options_preprocessing} \x02$text"); + $text =~ s/^\x02//; + } + + # Process $text line by line + + $text =~ s/\\n/\n/g; + $text =~ s/\n$//; + while ($text =~ /(.*?)(\n|$)/g) { + my $line = $1; + + # Exit while loop when finished + + last if ($2 ne "\n" && $1 eq ""); + + # Dauify text + + my $newtext = parse_text("$options $line") . "\n"; + + $output .= $newtext; + + # The parsed text ($newtext) can contain more than one line. + # All $newtext lines have the same command. + # The command (MSG, ACTION, ...) has to be remembered. + + while ($newtext =~ /\n/g) { + $babble{command_out_history}{$counter} = $command_out; + $babble{command_out_history_switch}{$counter} = $command_out_activated; + $counter++; + } + } + + # Lines are separated by newline characters. Maybe there are to many of + # them at the end of the string (probably produced by --figlet, --cowsay, ...). + # That's disturbing the number of lines calculation later. + + $output =~ s/\n{2,}$/\n/; + + # $output contains now the text to be babbled. It will be split by + # newlines by the babble subroutines and each line will be babbled with + # the correct commands restored. + + return $output; +} + +sub babble_interval { + return "BABBLE_INTERVAL=" . babble_set_interval(@_) . "\x02"; +} + +sub babble_set_interval { + my ($time, $accuracy) = @_; + + my $interval = time_parse($time); + + my $addend; + if ($accuracy == 100) { + $addend = 0; + } elsif ($accuracy > 0 && $accuracy < 100) { + $addend = rand($interval - ($interval * ($accuracy / 100))); + } else { + print_err('Invalid accuracy value'); + return; + } + + if (int(rand(2))) { + $interval = $interval + $addend; + } else { + $interval = $interval - $addend; + } + + $interval = int($interval); + + if ($interval < 10 || $interval > 1000000000) { + print_err('Invalid interval value'); + return 0; + } + + return $interval; +} + +sub babble_start { + my ($channel_rec, $text, $remote) = @_; + + # These are some global variables for the writing timer + + $babble{channel} = $channel_rec; + $babble{counter} = 0; + $babble{text} = "$text\n"; + $babble{numberoflines} = 0; + $babble{numberoflines}++ while ($babble{text} =~ /\n/g); + $babble{numberoflines} -= 1; + $babble{remote} = $remote; + + Irssi::timeout_remove($babble{timer_writing}) if (defined($babble{timer_writing})); + + timer_babble_writing_reset(); +} + +sub build_nick_mode_struct { + undef(%nick_mode); + + foreach my $server (Irssi::servers()) { + my $network_name = lc($server->{tag}); + + foreach my $channel ($server->channels()) { + my $channel_name = lc($channel->{name}); + my $op = $channel->{ownnick}{op}; + my $voice = $channel->{ownnick}{voice}; + + $nick_mode{$network_name}{$channel_name}{op} = $op; + $nick_mode{$network_name}{$channel_name}{voice} = $voice; + } + } +} + +sub daumode_channels { + my @items; + my $item; + while ($option{dau_daumode_channels} =~ /([^,]+)/g) { + my $match = $1; + if ($match =~ s/\\$//) { + $item .= "$match,"; + } else { + $item .= $match; + $item =~ s/^\s*//; + $item =~ s/\s*$//; + push @items, $item unless ($item =~ /^\s*$/); + $item = ""; + } + } + + foreach my $server (Irssi::servers()) { + my $network_name = $server->{tag}; + foreach my $channel ($server->channels()) { + my $channel_name = $channel->{name}; + foreach my $daumode (@items) { + $daumode =~ m#^([^/]+)/([^:]+):(.*)#; + my $item_channel = $1; + my $item_network = $2; + my $item_switches = $3; + + if (lc($item_channel) eq lc($channel_name) && + lc($item_network) eq lc($network_name)) + { + unless ($daumode{channels_in}{$network_name}{$channel_name} || + $daumode{channels_out}{$network_name}{$channel_name}) + { + $channel->print("%9dau.pl%9: Activating daumode according to setting dau_daumode_channels"); + } + $channel->command("dau --daumode $item_switches"); + } + } + } + } +} + +sub def_dau_cowsay_cowpath { + my $cowsay = $ENV{COWPATH} || '/usr/share/cowsay/cows'; + chomp($cowsay); + return $cowsay; +} + +sub def_dau_cowsay_cowsay_path { + my $cowsay = `which cowsay`; + chomp($cowsay); + return $cowsay; +} + +sub def_dau_cowsay_cowthink_path { + my $cowthink = `which cowthink`; + chomp($cowthink); + return $cowthink; +} + +sub def_dau_figlet_fontpath { + my $figlet = `figlet -I2`; + chomp($figlet); + return $figlet; +} + +sub def_dau_figlet_path { + my $figlet = `which figlet`; + chomp($figlet); + return $figlet; +} + +sub cowsay_cowlist { + my $cowsay_cowpath = shift; + + # clear cowlist + + %{ $switches{combo}{cowsay}{cow} } = (); + + # generate new list + + while (<$cowsay_cowpath/*.cow>) { + my $cow = (fileparse($_, qr/\.[^.]*/))[0]; + $switches{combo}{cowsay}{cow}{$cow} = 1; + } +} + +sub figlet_fontlist { + my $figlet_fontpath = shift; + + # clear fontlist + + %{ $switches{combo}{figlet}{font} } = (); + + # generate new list + + while (<$figlet_fontpath/*.flf>) { + my $font = (fileparse($_, qr/\..*/))[0]; + $switches{combo}{figlet}{font}{$font} = 1; + } +} + +sub fix { + my $string = shift; + $string =~ s/^\t+//gm; + return $string; +} + +sub output_text { + my ($thing, $target, $text) = @_; + + foreach my $line (split /\n/, $text) { + + # prevent "-!- Irssi: Not enough parameters given" + $line = ' ' if ($line eq ''); + + # --command -out <command>? + + if ($command_out_activated) { + if (defined($thing) && $thing) { + $thing->command("$command_out $line"); + } else { + my $server = Irssi::active_server(); + + if (defined($server) && $server && $server->{connected}) { + $server->command("$command_out $line"); + } else { + print CLIENTCRAP $line; + } + } + } + + # Not a channel/query window, --help, --changelog, ... + + elsif ($print_message) { + print CLIENTCRAP $line; + } + + # MSG or ACTION to channel or query + + elsif ($command_out eq 'ACTION' || $command_out eq 'MSG') { + $thing->command("$command_out $target $line"); + } + + # weird things happened... + + else { + print CLIENTCRAP $line; + } + } +} + +sub parse_text { + my ($data, $channel_rec) = @_; + my $output; + + $command_out_activated = 0; + $command_out = 'MSG'; + $counter_switches = 0; + $daumode_activated = 0; + $print_message = 0; + %queue = (); + + OUTER: while ($data =~ /^--(\w+) ?/g) { + + my $first_level_option = $1; + + # If its the first time we are in the OUTER loop, check + # if the first level option is one of the few options, + # which must not be combined. + + if (ref($switches{nocombo}{$first_level_option}{'sub'}) && $counter_switches == 0) { + + $data =~ s/^--\w+ ?//; + + # found a first level option + + $queue{$counter_switches}{$first_level_option} = { }; + + # Check for second level options and third level options. + # Get all of them and put theme in the + # $queue hash + + while ($data =~ /^-(\w+) ('.*?(?<![\\])'|\S+) ?/g) { + + my $second_level_option = $1; + my $third_level_option = $2; + + $third_level_option =~ s/^'//; + $third_level_option =~ s/'$//; + $third_level_option =~ s/\\'/'/g; + + # If $switches{nocombo}{$first_level_option}{$second_level_option}{'*'}: + # The user can give any third_level_option on the commandline + + my $any_option = + $switches{nocombo}{$first_level_option}{$second_level_option}{'*'} ? 1 : 0; + + if ($switches{nocombo}{$first_level_option}{$second_level_option}{$third_level_option} || + $any_option) + { + $queue{$counter_switches}{$first_level_option}{$second_level_option} = $third_level_option; + } + + $data =~ s/^-(\w+) ('.*?(?<![\\])'|\S+) ?//; + } + + # initialize some values + + foreach my $second_level_option (keys(%{ $switches{nocombo}{$first_level_option} })) { + if (!defined($queue{'0'}{$first_level_option}{$second_level_option})) { + $queue{'0'}{$first_level_option}{$second_level_option} = ''; + } + } + + # All done. Run the subroutine + + $output = &{ $switches{nocombo}{$first_level_option}{'sub'} }($data, $channel_rec); + + return $output; + } + + # Check for all those options that can be combined. + + elsif (ref($switches{combo}{$first_level_option}{'sub'})) { + + $data =~ s/^--\w+ ?//; + + # found a first level option + + $queue{$counter_switches}{$first_level_option} = { }; + + # Check for second level options and + # third level options. Get all of them and put them + # in the $queue hash + + while ($data =~ /^-(\w+) ('.*?(?<![\\])'|\S+) ?/g) { + + my $second_level_option = $1; + my $third_level_option = $2; + + $third_level_option =~ s/^'//; + $third_level_option =~ s/'$//; + $third_level_option =~ s/\\'/'/g; + + # If $switches{combo}{$first_level_option}{$second_level_option}{'*'}: + # The user can give any third_level_option on the commandline + + my $any_option = + $switches{combo}{$first_level_option}{$second_level_option}{'*'} ? 1 : 0; + + # known option => Put it in the hash + + if ($switches{combo}{$first_level_option}{$second_level_option}{$third_level_option} + || $any_option) + { + $queue{$counter_switches}{$first_level_option}{$second_level_option} = $third_level_option; + $data =~ s/^-(\w+) ('.*?(?<![\\])'|\S+) ?//; + } else { + last OUTER; + } + } + + # increase counter + + $counter_switches++; + } + + else { + last OUTER; + } + } + + # initialize some values + + for (my $i = 0; $i < $counter_switches; $i++) { + foreach my $first_level (keys(%{ $queue{$i} })) { + if (ref($switches{combo}{$first_level})) { + foreach my $second_level (keys(%{ $switches{combo}{$first_level} })) { + if (!defined($queue{$i}{$first_level}{$second_level})) { + $queue{$i}{$first_level}{$second_level} = ''; + } + } + } + } + } + + # text to subroutines + + $output = $data; + + # If theres no text left over, take one item of dau_random_messages + + if ($output eq '') { + $output = return_random_list_item($option{dau_standard_messages}); + } + + # No options? Get options from setting dau_standard_options and run + # parse_text() again + + if (keys(%queue) == 0) { + + if (!$counter_subroutines) { + print_out("No options given, hence using the value of the setting %9dau_standard_options%9 and that is %9$option{dau_standard_options}%9", $channel_rec); + $counter_subroutines++; + $output = parse_text("$option{dau_standard_options} $output", $channel_rec); + } else { + print_err('Invalid value for setting dau_standard_options. ' . + 'Will use %9--moron%9 instead!'); + $output =~ s/^\Q$option{dau_standard_options}\E //; + $output = parse_text("--moron $output", $channel_rec); + } + + } else { + + $counter_switches = 0; + + for (keys(%queue)) { + my ($first_level_option) = keys %{ $queue{$counter_switches} }; + $output = &{ $switches{combo}{$first_level_option}{'sub'} }($output, $channel_rec); + $counter_switches++; + } + } + + # reset subcounter + + $counter_subroutines = 0; + + # return text + + return $output; +} + +sub print_err { + my $text = shift; + + foreach my $line (split /\n/, $text) { + print CLIENTCRAP "%Rdau.pl error%n: $line"; + } +} + +sub print_out { + my ($text, $channel_rec) = @_; + + if ($option{dau_silence}) { + return; + } + + foreach my $line (split /\n/, $text) { + my $message = "%9dau.pl%9: $line"; + if (defined($channel_rec) && $channel_rec) { + $channel_rec->print($message); + } else { + print CLIENTCRAP $message; + } + } +} + +# return_option('firstlevel', 'secondlevel'): +# +# If "--firstlevel -secondlevel value" given on the commandline, return 'value'. +# +# return_option('firstlevel', 'secondlevel', 'default value'): +# +# If "--firstlevel -secondlevel value" not given on the commandline, return +# 'default value'. +sub return_option { + if (@_ == 2) { + return $queue{$counter_switches}{$_[0]}{$_[1]}; + } elsif (@_ == 3) { + if (length($queue{$counter_switches}{$_[0]}{$_[1]}) > 0) { + return $queue{$counter_switches}{$_[0]}{$_[1]}; + } else { + return $_[2]; + } + } else { + return 0; + } +} + +sub return_random_list_item { + my $arg = shift; + my @strings; + + my $item; + while ($arg =~ /([^,]+)/g) { + my $match = $1; + if ($match =~ s/\\$//) { + $item .= "$match,"; + } else { + $item .= $match; + $item =~ s/^\s*//; + $item =~ s/\s*$//; + push @strings, $item; + $item = ""; + } + } + + if (@strings == 0) { + return; + } else { + return $strings[rand(@strings)]; + } +} + +sub set_settings { + # setting changed/added => change/add it here + + # boolean + $option{dau_away_quote_reason} = Irssi::settings_get_bool('dau_away_quote_reason'); + $option{dau_away_reminder} = Irssi::settings_get_bool('dau_away_reminder'); + $option{dau_babble_verbose} = Irssi::settings_get_bool('dau_babble_verbose'); + $option{dau_color_choose_colors_randomly} = Irssi::settings_get_bool('dau_color_choose_colors_randomly'); + $option{dau_cowsay_print_cow} = Irssi::settings_get_bool('dau_cowsay_print_cow'); + $option{dau_figlet_print_font} = Irssi::settings_get_bool('dau_figlet_print_font'); + $option{dau_silence} = Irssi::settings_get_bool('dau_silence'); + $option{dau_statusbar_daumode_hide_when_off} = Irssi::settings_get_bool('dau_statusbar_daumode_hide_when_off'); + $option{dau_tab_completion} = Irssi::settings_get_bool('dau_tab_completion'); + + # Integer + $option{dau_babble_history_size} = Irssi::settings_get_int('dau_babble_history_size'); + $option{dau_babble_verbose_minimum_lines} = Irssi::settings_get_int('dau_babble_verbose_minimum_lines'); + $option{dau_cool_maximum_line} = Irssi::settings_get_int('dau_cool_maximum_line'); + $option{dau_cool_probability_eol} = Irssi::settings_get_int('dau_cool_probability_eol'); + $option{dau_cool_probability_word} = Irssi::settings_get_int('dau_cool_probability_word'); + $option{dau_remote_babble_interval_accuracy} = Irssi::settings_get_int('dau_remote_babble_interval_accuracy'); + + # String + $option{dau_away_away_text} = Irssi::settings_get_str('dau_away_away_text'); + $option{dau_away_back_text} = Irssi::settings_get_str('dau_away_back_text'); + $option{dau_away_options} = Irssi::settings_get_str('dau_away_options'); + $option{dau_away_reminder_interval} = Irssi::settings_get_str('dau_away_reminder_interval'); + $option{dau_away_reminder_text} = Irssi::settings_get_str('dau_away_reminder_text'); + $option{dau_babble_options_line_by_line} = Irssi::settings_get_str('dau_babble_options_line_by_line'); + $option{dau_babble_options_preprocessing} = Irssi::settings_get_str('dau_babble_options_preprocessing'); + $option{dau_color_codes} = Irssi::settings_get_str('dau_color_codes'); + $option{dau_cool_eol_style} = Irssi::settings_get_str('dau_cool_eol_style'); + $option{dau_cowsay_cowlist} = Irssi::settings_get_str('dau_cowsay_cowlist'); + $option{dau_cowsay_cowpath} = Irssi::settings_get_str('dau_cowsay_cowpath'); + $option{dau_cowsay_cowpolicy} = Irssi::settings_get_str('dau_cowsay_cowpolicy'); + $option{dau_cowsay_cowsay_path} = Irssi::settings_get_str('dau_cowsay_cowsay_path'); + $option{dau_cowsay_cowthink_path} = Irssi::settings_get_str('dau_cowsay_cowthink_path'); + $option{dau_daumode_channels} = Irssi::settings_get_str('dau_daumode_channels'); + $option{dau_delimiter_string} = Irssi::settings_get_str('dau_delimiter_string'); + $option{dau_figlet_fontlist} = Irssi::settings_get_str('dau_figlet_fontlist'); + $option{dau_figlet_fontpath} = Irssi::settings_get_str('dau_figlet_fontpath'); + $option{dau_figlet_fontpolicy} = Irssi::settings_get_str('dau_figlet_fontpolicy'); + $option{dau_figlet_path} = Irssi::settings_get_str('dau_figlet_path'); + $option{dau_files_away} = Irssi::settings_get_str('dau_files_away'); + $option{dau_files_babble_messages} = Irssi::settings_get_str('dau_files_babble_messages'); + $option{dau_files_cool_suffixes} = Irssi::settings_get_str('dau_files_cool_suffixes'); + $option{dau_files_root_directory} = Irssi::settings_get_str('dau_files_root_directory'); + $option{dau_files_substitute} = Irssi::settings_get_str('dau_files_substitute'); + $option{dau_language} = Irssi::settings_get_str('dau_language'); + $option{dau_moron_eol_style} = Irssi::settings_get_str('dau_moron_eol_style'); + $option{dau_parse_special_list_delimiter} = Irssi::settings_get_str('dau_parse_special_list_delimiter'); + $option{dau_random_options} = Irssi::settings_get_str('dau_random_options'); + $option{dau_remote_babble_channellist} = Irssi::settings_get_str('dau_remote_babble_channellist'); + $option{dau_remote_babble_channelpolicy} = Irssi::settings_get_str('dau_remote_babble_channelpolicy'); + $option{dau_remote_babble_interval} = Irssi::settings_get_str('dau_remote_babble_interval'); + $option{dau_remote_channellist} = Irssi::settings_get_str('dau_remote_channellist'); + $option{dau_remote_channelpolicy} = Irssi::settings_get_str('dau_remote_channelpolicy'); + $option{dau_remote_deop_reply} = Irssi::settings_get_str('dau_remote_deop_reply'); + $option{dau_remote_devoice_reply} = Irssi::settings_get_str('dau_remote_devoice_reply'); + $option{dau_remote_op_reply} = Irssi::settings_get_str('dau_remote_op_reply'); + $option{dau_remote_permissions} = Irssi::settings_get_str('dau_remote_permissions'); + $option{dau_remote_question_regexp} = Irssi::settings_get_str('dau_remote_question_regexp'); + $option{dau_remote_question_reply} = Irssi::settings_get_str('dau_remote_question_reply'); + $option{dau_remote_voice_reply} = Irssi::settings_get_str('dau_remote_voice_reply'); + $option{dau_standard_messages} = Irssi::settings_get_str('dau_standard_messages'); + $option{dau_standard_options} = Irssi::settings_get_str('dau_standard_options'); + $option{dau_words_range} = Irssi::settings_get_str('dau_words_range'); +} + +sub signal_handling { + # complete word + + if ($option{dau_tab_completion}) { + if ($signal{'complete word'} != 1) { + Irssi::signal_add_last('complete word', 'signal_complete_word'); + } + $signal{'complete word'} = 1; + } else { + if ($signal{'complete word'} != 0) { + Irssi::signal_remove('complete word', 'signal_complete_word'); + } + $signal{'complete word'} = 0; + } + + # event privmsg + + if ($option{dau_remote_permissions} =~ /^1[01][01][01][01][01]$/) { + if ($signal{'event privmsg'} != 1) { + Irssi::signal_add_last('event privmsg', 'signal_event_privmsg'); + } + $signal{'event privmsg'} = 1; + } else { + if ($signal{'event privmsg'} != 0) { + Irssi::signal_remove('event privmsg', 'signal_event_privmsg'); + } + $signal{'event privmsg'} = 0; + } + + # nick mode changed + + if ($option{dau_remote_permissions} =~ /^[01]1[01][01][01][01]$/ || + $option{dau_remote_permissions} =~ /^[01][01]1[01][01][01]$/ || + $option{dau_remote_permissions} =~ /^[01][01][01]1[01][01]$/ || + $option{dau_remote_permissions} =~ /^[01][01][01][01]1[01]$/) + { + if ($signal{'nick mode changed'} != 1) { + Irssi::signal_add_last('channel joined', 'build_nick_mode_struct'); + Irssi::signal_add_last('nick mode changed', 'signal_nick_mode_changed'); + } + $signal{'nick mode changed'} = 1; + } else { + if ($signal{'nick mode changed'} != 0) { + Irssi::signal_remove('channel joined', 'build_nick_mode_struct'); + Irssi::signal_remove('nick mode changed', 'signal_nick_mode_changed'); + } + $signal{'nick mode changed'} = 0; + } + + # daumode: outgoing messages + + my $daumode_out = 0; + + foreach my $server (keys %{ $daumode{channels_out} }) { + foreach my $channel (keys %{ $daumode{channels_out}{$server} }) { + if ($daumode{channels_out}{$server}{$channel} == 1) { + $daumode_out = 1; + } + } + } + + if ($daumode_out) { + if ($signal{'send text'} != 1) { + Irssi::signal_add_first('send text', 'signal_send_text'); + } + $signal{'send text'} = 1; + } else { + if ($signal{'send text'} != 0) { + Irssi::signal_remove('send text', 'signal_send_text'); + } + $signal{'send text'} = 0; + } + + # daumode: incoming messages + + my $daumode_in = 0; + + foreach my $server (keys %{ $daumode{channels_in} }) { + foreach my $channel (keys %{ $daumode{channels_in}{$server} }) { + if ($daumode{channels_in}{$server}{$channel} == 1) { + $daumode_in = 1; + } + } + } + + if ($daumode_in) { + if ($signal{'daumode in'} != 1) { + Irssi::signal_add_last('message public', 'signals_daumode_in'); + Irssi::signal_add_last('message irc action', 'signals_daumode_in'); + } + $signal{'daumode in'} = 1; + } else { + if ($signal{'daumode in'} != 0) { + Irssi::signal_remove('message public', 'signals_daumode_in'); + Irssi::signal_remove('message irc action', 'signals_daumode_in'); + } + $signal{'daumode in'} = 0; + } + + # continuing babbles, setting daumode + + if ($signal{'channel joined'} != 1) { + Irssi::signal_add_last('channel joined', 'signal_channel_joined'); + Irssi::signal_add_last('channel destroyed', 'signal_channel_destroyed'); + $signal{'channel joined'} = 1; + } + + # Cancel babble when message could not be sent to channel + + if ($signal{'event 404'} != 1) { + Irssi::signal_add_last('event 404', 'signal_event_404'); + $signal{'event 404'} = 1; + } +} + +sub time_diff_verbose { + my ($sub1, $sub2) = @_; + + my $difference = $sub1 - $sub2; + $difference *= (-1) if ($difference < 0); + my $seconds = $difference % 60; + $difference = ($difference - $seconds) / 60; + my $minutes = $difference % 60; + $difference = ($difference - $minutes) / 60; + my $hours = $difference % 24; + $difference = ($difference - $hours) / 24; + my $days = $difference % 7; + my $weeks = ($difference - $days) / 7; + + my $time; + $time = "$weeks week" . ($weeks == 1 ? "" : "s") . ", " if ($weeks); + $time .= "$days day" . ($days == 1 ? "" : "s") . ", " if ($weeks || $days); + $time .= "$hours hour" . ($hours == 1 ? "" : "s") . ", " if ($weeks || $days || $hours); + $time .= "$minutes minute" . ($minutes == 1 ? "" : "s") . ", " if ($weeks || $days || $hours || $minutes); + $time .= "$seconds second" . ($seconds == 1 ? "" : "s") if ($weeks || $days || $hours || $minutes || $seconds); + + return $time; +} + +sub time_parse { + my $time = $_[0]; + my $parsed_time = 0; + + # milliseconds + while ($time =~ s/(\d+)\s*(?:milliseconds|ms)//g) { + $parsed_time += $1; + } + # seconds + while ($time =~ s/(\d+)\s*s(?:econds?)?//g) { + $parsed_time += $1 * 1000; + } + # minutes + while ($time =~ s/(\d+)\s*m(?:inutes?)?//g) { + $parsed_time += $1 * 1000 * 60; + } + # hours + while ($time =~ s/(\d+)\s*h(?:ours?)?//g) { + $parsed_time += $1 * 1000 * 60 * 60; + } + # days + while ($time =~ s/(\d+)\s*d(?:ays?)?//g) { + $parsed_time += $1 * 1000 * 60 * 60 * 24; + } + # weeks + while ($time =~ s/(\d+)\s*w(?:eeks?)?//g) { + $parsed_time += $1 * 1000 * 60 * 60 * 24 * 7; + } + + if ($time !~ /^\s*$/) { + print_err('Error while parsing the date!'); + return 0; + } + + return $parsed_time; +} + +################################################################################ +# Debugging +################################################################################ + +sub debug_message { + open(DEBUG, ">>", "$ENV{HOME}/.dau/.debug"); + + print DEBUG $_[0]; + + close (DEBUG); +} + +#BEGIN { +# use warnings; +# +# open(STDERR, ">>", $ENV{HOME}/.dau/.STDERR"); +#} |