diff options
Diffstat (limited to '')
-rw-r--r-- | scripts/findbot.pl | 984 |
1 files changed, 984 insertions, 0 deletions
diff --git a/scripts/findbot.pl b/scripts/findbot.pl new file mode 100644 index 0000000..753fc31 --- /dev/null +++ b/scripts/findbot.pl @@ -0,0 +1,984 @@ +############################################################################### +# Find script that searches your local files and sends them to users +# Copyright (C) 2003 Thomas Karlsson +# +# Findbot script, which responds to @find commands in irc channels +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Thomas Karlsson (findbot@planet.eu.org) +# +############################################################################### +# Description: +# +# This script loads into an Irssi client and then monitors selected channels +# and replies to public channel commands. +# The commands are: +# @find : searches the summaryfile after file "@find birthday" looks for +# a file containing birthday. +# @<botnick>-stats : Replies with the users queue. +# @<botnick>-remove : Will remove the users whole queue +# @<botnick>-remove 2 : Will remove queue position 2 from the queue +# @<botnick>-help : Will message the help to the user. +# !<botnick> <filename> :Will queue the file. For eg."!santa_claus jingle.bells.mp3" +# +############################################################################### +# Installation: +# +# AT THE END OF THIS FILE IS ALL INSTALLATION INSTRUCTIONS!! +# +# Variables: +# findbot_channels - Space separated channels (#mp3 #othermp3) +# findbot_summaryfile - Full path to the "mymp3s.txt" file (/misc/mp3/mymp3s.txt) +# findbot_sendlist - Full path and filename to the list that is sent to clients +# findbot_maxresults - Max findresults returned to the requesting client +# findbot_maxqueue - Max files allowed in the queue +# findbot_maxsends - Max simultanous sends allowed +# findbot_maxuserqueue - Max queued files per Nick +# findbot_maxusersends - Max simultanous sends per Nick +# findbot_showbanner - Present a banner in every "findbot_channels" channel +# findbot_bannertime - How many seconds between each banner +# findbot_minspeed - Minimum CPS for a send, 10000 means 10kb/s, 0 means disabled +# findbot_mustbeinchannel - If ON, the user is required to be in the channel during download +# findbot_debuglevel - Debuglevel, Higher value equals more debugoutput +# findbot_enabled - Set ON or OFF +# findbot_timeslots - When the server should be enabled (sat=10:00-18:00sun=00:00-23:59) +# If a day can't be found the bot will be ON by default +# findbot_voicegetpriority - If ON then voiceuserusers and ops will get priority in the queue. +# Ops get 20 in priority and voice gets 10. I.e ops are more prioritized than voice +# +# Admincommands: +# /findbotqueue - Shows you the whole queue in the findbot window +# /findbotremove - Admin removes queueitems +# /findbotreset - If you like you can specify how many sends the script thinks it have. This was just added +# if you wanted to send somefiles your self without the script sending files. +# /findbotreload - Reloads the summaryfile if you have added files +# /findbotactivesends - Show which users are currently having a download +# +############################################################################### +# TODO or maybe features +# +# * When requesting it SHOULD be case sensitive +# * Support CTCP SLOTS and CTCP MP3, seems unnecessary to help windows-mirc users :) +# Slots Free Next Queues Max Sendspeed Files +# 4 4 NOW 0 999 0 120575 36856591362 0 1073595728 1 +# * Make an ignore and ban function +# * Should the users see the whole que or just their own files? +# * If there is a netsplit all downloads will be cancelled if an active user disappered +# * If one send is below like 4kb/s then change findbot_maxsends to one more, so we use the bandwidth +# * DONE Servers (i.e +v) should get priority, but how? First in queue? +# * DONE Fix admin_showqueue to really show VIP instead of 1 +############################################################################### +# CHANGES +# +# 1.58 * requesting in a private message is allowed when user is in a monitored channel +# * filelist creation script at the bottom of this script has been changed to support utf8, multiple folders, with or without file and 7z compression of the command list +# 1.57 * Added a VIP function which allows +v users to be first in line to get a file +# * Remove a users queue if they get kicked (only if findbot_mustbeinchannel is ON) +# * Fixed a bug when a user with a download changed nick. +# 1.56 * The findbot_maxqueue now works +# * Sending files with spaces in them, now works +# 1.55 * Minor changes +# 1.54 * Added support to update the mp3list without restarting the bot (/findbotreload) +# 1.53 * Fixed some debug output +# 1.52 * Fixed some typos +# * Now people can't look for * . etc. Now a searchpattern MUST contain atleast 1 normal character +# * Fixed so you can change banner time without restarting the bot +# 1.50 * Added a timeslot function +# * Added logging support. Now logging to file. Must specify filename and path INSIDE this script +# 1.06 * "Optimized" search. Instead of opening and read the whole summaryfile everytime +# someone searched the script reads the file once at startup. +# * Fixed more regular expressions +# * Added multiserver support, i.e you can have the bot on two nets and two different channels +# 1.05 * Added a new perlscript at the end of this file. +# It searches your mp3s and makes the 2 necessary files. +# The script is made by Henrik Andreasson (findbot@han.pp.se) +# 1.04 * Changed so the files contains full path to mp3s +# * findbot_maxsends was ignored under some circumstanses +# * Added so debugoutput shows which file are sent +# * Sending to client "Now sending you file...." only if they accually are in the channel +# 1.03 * Changed a "for-loop" one bit +# * If findbot_minimumspeed was disabled, then the user could leave channel +# and still get files even if findbot_mustbeinchannel was enabled +# * Forgot to write to debugwindow if someone downloaded the whole list +# * Corrected some bad english :) +# * Fixed more regular expressions +# * The user will be told the queueposition when requesting a file +# * Fixed some queueproblems +# * Added some errormessages if someone types !nickname in a private message +# 1.01 * Do not reply with "no match" if no match was found to avoid unnecessary spam +# * Removed alot of commented code +# * Changed the description of the script +# * Changed the "results found" string a bit. +# * Added a new value findbot_sendlist and separated the filelist and the one which accually is sent to the users +# * Fixed some regular expressions to fit the new searchfiles +# * Bug fix. If someone resumed a file, they always will be under findbot_minspeed in the start +# * Didn't search if someone typed @FIND (in uppercase) +# * Ops the url wasn't right. There is no ~ in the address :) +# 1.0 Release +############################################################################### +use Irssi; +use Irssi::Irc; +use strict; +use vars qw($VERSION %IRSSI); + +$VERSION = "1.58"; + +%IRSSI = ( + authors => "Thomas Karlsson", + contact => "findbot\@planet.eu.org", + name => "Findbot", + description => "Public command \@find script", + license => "GPL", + url => "http://hem.passagen.se/thka2315/", +); + +my %nickqueue = (); # Queuenumber + nickname +my %filequeue = (); # Queuenumber + filename +my %servertagqueue = (); # Queuenumber + array with servertag,voiceprio,extrafield +my %activesends = (); # nickname + 1 The user is here if he has an active send +my $lastqueuenumber = 0; # Holds the last queueitem +my %scriptdetect = (); +my $timeout_tag; +my $banner_timeout; +my $currentsends = 0; +my $servertag; +my $globalstart = 0; +my $globalvippos = 0; +my $debuglevel; +my %bannedpeople = (); # This will contain banned people and time of ban +my @bigarray; # In here the whole filelist will reside +my @daynames = qw(Sun Mon Tue Wed Thu Fri Sat); +my $logfile = "findbot.log"; +my $scriptdetecttime = "3"; # Three seconds must pass before a new filerequest is issued, after a DCC CLOSE +my $showscriptdetect = 1; +my $lastbannerprint = time(); # The last time the banner was printed into monitored channels + +sub timeslotenabled { + my $weekday = shift; # Save weekday + my $slothour = shift; # Save hours + my $slotminute = shift; # Save minutes + + $weekday = $daynames[$weekday]; + my $timeslotstring = Irssi::settings_get_str('findbot_timeslots'); + if ( $timeslotstring =~ /$weekday/i ) { + if ( $timeslotstring =~ m/.*$weekday=(.?.):(.?.)(a\.?m\.?|p\.?m\.?)?-(.?.):(.?.)(a\.?m\.?|p\.?m\.?)?.*/i ) { + my $fromhour = $1; + my $frommin = $2; + my $fromampm = $3; + my $tohour = $4; + my $tomin = $5; + my $toampm = $6; + if ( $fromampm =~ /p/i ) { $fromhour += 12; } # If it is a pm time add 12 to get 24h format + if ( $toampm =~ /p/i ) { $tohour += 12; } # If it is a pm time add 12 to get 24h format + my $midnightfrom = ( $fromhour * 60 ) + $frommin; # Get minutes from midnight + my $midnightto = ( $tohour * 60 ) + $tomin; # Get minutes from midnight + my $inputtime = ( $slothour * 60 ) + $slotminute; # Get minutes from midnight + debugprint(20,"inputtime:$inputtime midfrom:$midnightfrom midto:$midnightto"); + if ( $inputtime <= $midnightto && $inputtime >= $midnightfrom ) { + return 1; # The time is between the timeenabled slot + } else { + return 0; # Time was outside. Bot should be off. + } + } else { + return 0; # Hmm didnt get the times in that day, maybe wrong input from user + } + } else { + return 1; # If the current day wasn't found in findbot_timeslots then return true, i.e bot is default ON. + } + return 0; # Return false i.e +} + +sub private_get { + (my $server, my $message, my $nick, my $address) = @_; + if ( $message =~ /^!$server->{nick}\ .*/i ) { + $server->command("/MSG " . $nick . " Please request files in the channel, not personally to me. Type \@$server->{nick}-help in channel for help"); + } elsif ( $message =~ /^\@$server->{nick}.*/i ) { + $server->command("/MSG " . $nick . " Please request my filelist in the channel, not personally to me. Type \@$server->{nick}-help in channel for help"); + } elsif ( $message =~ /^\@find.*/i ) { + $server->command("/MSG " . $nick . " Please search files in the channel, not personally to me. Type \@$server->{nick}-help in channel for help"); + } +} + +sub check_user_queued_items { + my $user = shift; # Get the nickname to check + my $localsrvtag = shift; + my $counter = 0; # Reset the counter + for ( my $i=1; $i <= $lastqueuenumber; $i++ ) { # Loop through entire queue + if ( $nickqueue{$i} eq $user && $localsrvtag eq $servertagqueue{$i}[0] ) { + $counter++; + } + } + return $counter; +} + +sub already_queued_file { + my $checknick = shift; + my $checkfile = shift; + my $srvtag = shift; + my $alreadyqueued = 0; + for ( my $i=1; $i <= $lastqueuenumber; $i++ ) { # Loop through entire queue + if ( $nickqueue{$i} eq $checknick && $filequeue{$i} eq $checkfile && $servertagqueue{$i}[0] eq $srvtag) { # Check if its queued + $alreadyqueued = 1; # Yep it was + } + } + if ( $alreadyqueued ) { return 1; } else { return 0; } # Return true if queued else false +} + +sub add_file_to_queue { + (my $addnick, my $addfile, my $srvtag, my $priority) = @_; # Split nickname and filename into two variables + $lastqueuenumber++; + $nickqueue{$lastqueuenumber} = $addnick; # for eg. $nickqueue{1} = 'El_Tomten' + $filequeue{$lastqueuenumber} = $addfile; # for eg. $filequeue{1} = '/misc/legal-mp3s/happy.birthday.mp3' + if ( ! Irssi::settings_get_bool('findbot_voicegetpriority') ) { $priority = 0; } + my @field = ($srvtag,$priority,"To be used later, maybe"); + $servertagqueue{$lastqueuenumber} = \@field; # for eg. $servertagqueue{1} = 'stockholm' + if ( $priority > 1 ) { # Did a priority user queued the file + fix_vip_position($priority); # Move vip position up to number one, or just after the last already existing vip position + } +} + +sub fix_vip_position { + my $priority = shift; # Get priority from input + my ($tnickqueue,$tfilequeue,$tservertagqueue); + if ( $lastqueuenumber eq 1 ) { return; } # If the queue only have one entry, why try to make it a priority? + for ( my $i = $lastqueuenumber; $i > 1; $i--) { + if ( $servertagqueue{$i-1}[1] >= $priority ) { $globalvippos = $i; last; } # Is the queue entry before a vip entry? Lets quit the prioritymove + $tnickqueue = $nickqueue{$i-1}; # Backup entry + $tfilequeue = $filequeue{$i-1}; + $tservertagqueue = $servertagqueue{$i-1}; + + $nickqueue{$i-1} = $nickqueue{$i}; # Move entry up + $filequeue{$i-1} = $filequeue{$i}; + $servertagqueue{$i-1} = $servertagqueue{$i}; + + $nickqueue{$i} = $tnickqueue; # Restore entry ( the two entris have now changed place ) + $filequeue{$i} = $tfilequeue; + $servertagqueue{$i} = $tservertagqueue; + } +} + +sub remove_queueitem { + my $queueitem = shift; + if (defined($nickqueue{$queueitem}) && defined($filequeue{$queueitem} && defined($servertagqueue{$queueitem})) ) { # Is there really a queueitem here? + for ( my $i = $queueitem; $i <= Irssi::settings_get_int('findbot_maxqueue'); $i++) { + if ( defined($nickqueue{$i+1}) && defined($filequeue{$i+1}) && defined($servertagqueue{$i+1}) ) { # Move up in queue if there is one + $nickqueue{$i} = $nickqueue{$i+1}; # Move up in queue + $filequeue{$i} = $filequeue{$i+1}; # Move up in queue + $servertagqueue{$i} = $servertagqueue{$i+1}; # Move up in queue + } + + } + delete $nickqueue{$lastqueuenumber}; # Delete the last entry. It has been moved up one slot + delete $filequeue{$lastqueuenumber}; # Delete the last entry. It has been moved up one slot + delete $servertagqueue{$lastqueuenumber}; # Delete the last entry. It has been moved up one slot + $lastqueuenumber--; # Since we removed a queue item the lastqueuenumber decreases + } else { debugprint(10,"debug: No remove $queueitem"); } +} + +sub user_have_max_active_sends { + my $nickname = shift; # Save the nick + my $localserver = shift; # Save current servertag + if ( $activesends{$nickname} < Irssi::settings_get_int('findbot_maxusersends') ) { + return 0; # The user didn't have enough sends + } else { + return 1; # The user have NOT an active send + } +} + +sub user_is_in_active_channel { + my $nickname = shift; + my $srvtag = shift; + my $find_channels = Irssi::settings_get_str('findbot_channels'); # What channels to monitor + my @checkchannels = split (/ /, $find_channels); # Split into an array + + foreach my $localserver ( Irssi::servers() ) { # Loop through all connected servers + foreach my $singlechan ( @checkchannels ) { # Loop through all monitored channels + my $channel = $localserver->channel_find($singlechan); # Get a channelobject + if ( defined($channel) && defined($channel->nick_find($nickname)) ) { # Is the nick there? + return 1; # User are in monitored channels # Yep is was + } + } + } + return 0; # User have left monitored channels + +} + +sub nicefilename { + my $filename = shift; + + if ( $filename =~ /.*\/(.*)\ *:.*/g ) { # If filelist is made by "file" + debugprint(15,"Summary file is made by the program file"); + return $1; + } elsif ( $filename =~ /.*\/(.*)$/g ) { # If filelist is Not made by file + debugprint(15,"Summary file is NOT made by the program file"); + return $1; + } +} + +sub strippath { + my $filename = shift; # Get parameter into $filename + + $filename =~ s/.*\/(.*)/$1/g; # Remove everything until the last / + return $filename; # Return the stripped line +} + +sub debugprint { + (my $dbglvl,my $debugmessage) = @_; # Save input to variables + $debuglevel = Irssi::settings_get_int('findbot_debuglevel'); + my $win; + if ( ! ($win = Irssi::window_find_name($IRSSI{name})) ) { # If the windows doesn't exist + $win = Irssi::Windowitem::window_create($IRSSI{name},1); + } + if ( $dbglvl <= $debuglevel ) { + $win->set_name($IRSSI{name}); # Select the window + $win->print($debugmessage,MSGLEVEL_CLIENTCRAP); + my $debugtid = localtime(time); + open (LOGFILE,">>", $logfile); + print LOGFILE "$debugtid: $debugmessage\n"; + close (LOGFILE); + } +} + +sub process_queue { + if (Irssi::settings_get_bool('findbot_enabled') ) { # Is the findbot enabled? + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); # Get current time + if ( ! timeslotenabled($wday,$hour,$min) ) { # If NOT true the bot is offline + debugprint(15,"The bot is Offline due to timerestrictions in findbot_timeslots"); + return 0; + } + print_banner(); + if ( $currentsends < Irssi::settings_get_int('findbot_maxsends') ) { # Check if we'll send another file simultanously + my $i = 1; + while ( $i <= $lastqueuenumber ) { + if ( ! user_have_max_active_sends($nickqueue{$i},$servertagqueue{$i}[0]) ) { # If NOT user have max active sends + my $nicefile = nicefilename($filequeue{$i}); + if ( user_is_in_active_channel($nickqueue{$i},$servertagqueue{$i}[0]) ) { # Are the user in a monitored channel? + debugprint(10,"[ADMIN] $nickqueue{$i} is in monitored channels, sending $nicefile"); + my $localserver = Irssi::server_find_tag($servertagqueue{$i}[0]); + $localserver->command("/QUOTE NOTICE " . $nickqueue{$i} . " :Sending you the requested file: $nicefile"); + $localserver->command("/DCC SEND $nickqueue{$i} \"$filequeue{$i}\"" ); + remove_queueitem($i); + last; # Exit the loop + } else { + debugprint(10,"[ADMIN] $nickqueue{$i} is NOT in monitored channels. Removing queueentry $filequeue{$i}"); + remove_queueitem($i); + } # Remove the queued item if the user have parted the channel + } else { # A user had too many sends, increase $i by one to check next queue pos. + $i++; # Increase by one so we can loop through whole queue + } + } # End while or for + } + } + check_dcc_speed_and_in_channel(); # Check minimumspeed +} + +sub dcc_created { + (my $dcc) = @_; # Put active dcc in variable + + debugprint(15,"dcc_created was called"); + if ( $dcc->{type} eq "SEND" ) { # Is it a SEND? + if ( defined( $activesends{$dcc->{nick}} ) ) { + $activesends{$dcc->{nick}} = $activesends{$dcc->{nick}} + 1; + } else { + $activesends{$dcc->{nick}} = 1; + } + $currentsends++; + } +} + +sub dcc_closed { + (my $dcc) = @_; # Put active dcc in variable + + debugprint(15,"dcc_closed was called"); + if ( $dcc->{type} eq "SEND" && defined ($activesends{$dcc->{nick}}) ) { # Is it a SEND and a findbot SEND? + my $tiden = time(); + $tiden = $tiden - $dcc->{starttime}; + if ( $tiden > 0 ) { + my $kbsec = $dcc->{transfd} / $tiden; + } else { + $tiden = 1; + my $kbsec = $dcc->{transfd} / $tiden; + } + if ( $dcc->{transfd} == 0 ) { # If transfered byts are zero, then it was probably aborted + debugprint(10,"[ADMIN] SEND aborted Nick: $dcc->{nick} File: $dcc->{arg}"); + } else { + debugprint(10,"[ADMIN] SEND done Nick: $dcc->{nick} File: $dcc->{arg} Bytes: $dcc->{transfd} Time(sec): $tiden Speed: " . calc_kb_sec($tiden,$dcc->{transfd}) . " KB/s"); + } + if ($activesends{$dcc->{nick}} == 1) { + delete $activesends{$dcc->{nick}}; + } else { + $activesends{$dcc->{nick}} = $activesends{$dcc->{nick}} - 1; + } + $currentsends--; + $scriptdetect{$dcc->{nick}} = time(); # Record the time when dcc was closed + } +} + +sub calc_kb_sec { + my $seco = shift; + my $bytest = shift; + +my $kbsec = $bytest / $seco / 1000; + $kbsec =~ s/(.*\..?.?).*/$1/; + + return $kbsec; +} + +sub dcc_destroyed { + (my $dcc) = @_; # Put active dcc in variable + + debugprint(15,"dcc_destroyed was called"); +} + +sub check_dcc_speed_and_in_channel { +# my $localserver = Irssi::server_find_tag($servertag); # Get serverobject + my $minimumspeed = Irssi::settings_get_int('findbot_minspeed'); + my $channelcheck = Irssi::settings_get_bool('findbot_mustbeinchannel'); + foreach my $dccconnection (Irssi::Irc::dccs()) { + if ( $dccconnection->{type} eq "SEND" && defined($activesends{$dccconnection->{nick}}) && ($dccconnection->{transfd} - $dccconnection->{skipped}) > 50000) { # Check if its a findbot send. + my $bytetransferred = $dccconnection->{transfd} - $dccconnection->{skipped}; + my $timedownloaded = time() - $dccconnection->{starttime}; + if ( $timedownloaded == 0 ) { $timedownloaded++; } # Fix for Illegal division by zero + my $currentcps = sprintf("%02d",($bytetransferred / $timedownloaded)); # Get current CPS + if ( $currentcps < $minimumspeed && $minimumspeed > 0 ) { # Check if below minimumspeed + my $localserver = Irssi::server_find_tag($dccconnection->{servertag}); + $localserver->command("/QUOTE NOTICE $dccconnection->{nick} :Minimum CPS is $minimumspeed and you only have $currentcps. Closing your connection"); + $localserver->command("/DCC CLOSE SEND $dccconnection->{nick}"); + debugprint(10,"[ADMIN] $dccconnection->{nick} ($currentcps) is below minimumspeed($minimumspeed). Closing..."); + } elsif ( $channelcheck ) { + if ( ! user_is_in_active_channel($dccconnection->{nick},$dccconnection->{servertag}) ) { + debugprint(10,"[ADMIN] $dccconnection->{nick} has LEFT monitored channels, closing SEND"); + my $localserver = Irssi::server_find_tag($dccconnection->{servertag}); + $localserver->command("/DCC CLOSE SEND $dccconnection->{nick}"); + # Just close without warning, why bother to tell him if he's left. + } + } + } + } +} + +sub nickname_changed { + my ($chan, $newnick, $oldnick) = @_; + + foreach my $queuepos (keys(%nickqueue)) { # Go through all nicks in my queuelist to see if we're affected + if ( $nickqueue{$queuepos} eq $oldnick ) { # Check the nick + $nickqueue{$queuepos} = $newnick->{nick}; # Insert the new nick in that position + debugprint(10,"[ADMIN] Nickchange $nickqueue{$queuepos} -> $newnick->{nick}"); + } + } + if ( defined($activesends{$oldnick}) ) { # He has an active send + $activesends{$newnick->{nick}} = $activesends{$oldnick}; # Make a new entry so he can't evade the dcc speed check + delete $activesends{$oldnick}; + } +} + +sub user_got_kicked { + my ($kchannel,$knick,$kkicker,$kaddress,$kreason) = @_; + my $mustbeinchannel = Irssi::settings_get_bool('findbot_mustbeinchannel'); + + if ( $mustbeinchannel ) { # Are we to punish this kicked user? + foreach my $queuepos (keys(%nickqueue)) { # Go through all nicks in my queuelist to see if we're affected + if ( $nickqueue{$queuepos} eq $knick ) { # Check the nick if the kicked user has a queue. + debugprint(10,"[ADMIN] $knick was KICKED. Removing queueposition $queuepos $filequeue{$queuepos}"); + remove_queueitem($queuepos); # Removes the users queue + } + } + } +} + +sub print_banner { + my $timenow = time(); + my $timecalc = Irssi::settings_get_str('findbot_bannertime') + $lastbannerprint; +# debugprint(10,"print_banner function... now: $timenow last: $lastbannerprint timecalc: $timecalc"); + if ( $timenow > $timecalc ) { + $lastbannerprint = time(); # Reset timer + my $find_channels = Irssi::settings_get_str('findbot_channels'); # What channels to monitor + my @checkchannels = split (/ /, $find_channels); # Split into an array + if ( Irssi::settings_get_bool('findbot_showbanner') ) { # Check if I will print the banner + debugprint(10,"[ADMIN] Sending banner to monitored channels"); + my $showvoiceprio = "OFF"; + if (Irssi::settings_get_bool('findbot_voicegetpriority') ) { + $showvoiceprio = "ON"; + } + foreach my $localserver ( Irssi::servers() ) { + my $bannerad = "For my list of $#bigarray files type: \@" . $localserver->{nick} . ", Sends: $currentsends/" . Irssi::settings_get_int('findbot_maxsends') . " , Queue: $lastqueuenumber/" . Irssi::settings_get_int('findbot_maxqueue') . ", Voicepriority: $showvoiceprio, For help: \@" . $localserver->{nick} . "-help"; + foreach my $singlechan ( @checkchannels ) { # Loop through all monitored channels + my $channel = $localserver->channel_find($singlechan); # Get the channelobject + if ( defined($channel) ) { # Am I in the specific channel, if so its defined + $channel->command("/MSG $singlechan $bannerad" . " Using: Irssi " . $IRSSI{name} . " v$VERSION"); # Print banner + } # End if + } # End foreach channel + } # End foreach server + } # End if + } # End check if I'll print the banner +} + +sub admin_showqueue { + debugprint(10,"[ADMIN] Show queue"); + debugprint(10,"[ADMIN] Current sends are: $currentsends"); + for ( my $i = 1; $i <= $lastqueuenumber; $i++ ) { # Loop through the queue + debugprint(10,"[ADMIN] ($i) $nickqueue{$i}:$filequeue{$i}:$servertagqueue{$i}[0]:Prio $servertagqueue{$i}[1]"); +# if ( $servertagqueue{$i}[1] > 0 ) { # Is this a VIP entry? +# debugprint(10,"[ADMIN] ($i) $nickqueue{$i}:$filequeue{$i}:$servertagqueue{$i}[0]:VIP queued($servertagqueue{$i}[1])"); +# } else { +# debugprint(10,"[ADMIN] ($i) $nickqueue{$i}:$filequeue{$i}:$servertagqueue{$i}[0]:Normal queued"); +# } + } + debugprint(10,"[ADMIN] End of list"); +} + +sub admin_reset { + my $howmany = shift; + if ( $howmany =~ /\d+/ ) { + $currentsends = $howmany; # Reset current sends + debugprint(10,"[ADMIN] Current sends are now set to $currentsends"); + } else { + debugprint(10,"[ADMIN] Specify how many sends there are now"); + } +} + +#sub start_findbot { +# my($data,$localserver,$witem) = @_; + +# if ( $localserver != 0 ) { +# $servertag = $localserver->{tag}; # Remeber on which server the findbot is on +# $globalstart = 1; +# debugprint(10,"Findserver is started"); +# } else { +# debugprint(10,"Please start the server in a window where I can get hold of a servertag"); +#3 } +#} + +sub admin_removequeue { + my $queueposition = shift; + if ( $queueposition =~ /\d+/ ) { + remove_queueitem($queueposition); + debugprint(10,"[ADMIN] Removed position $queueposition"); + } else { + debugprint(10,"[ADMIN] Specify which queueitem should be removed"); + } +} + +sub admin_activesends { + debugprint(10,"[ADMIN] Listing active dccsends"); + foreach my $send (keys(%activesends)) { + debugprint(10,"[ADMIN] $send ($activesends{$send})"); + } + debugprint(10,"[ADMIN] End of list"); +} + +sub admin_reload { + if ( -r Irssi::settings_get_str('findbot_summaryfile') ) { + open (FINDFILE, "<", Irssi::settings_get_str('findbot_summaryfile')); # Open the file + @bigarray = <FINDFILE>; # Load it whole into memory :) + close (FINDFILE); + debugprint(10,"[ADMIN] Summary file has been reloaded into memory."); + } else { + debugprint(10,"[ADMIN] The Summaryfile cannot be read. Please check if the path is correct and the file is accually there."); + } +} + +sub send_ctcp_slots { +# Not implemented yet +} + +sub sanitize_input { + my $tainted_input = shift; + $tainted_input =~ s/[\^\\\[\]\$\(\)\?\+\/\|\'\}\{]+/\./g; # Translate ^\[]$()?+ to . + return $tainted_input; # Return regularexpression sanitized input +} + +sub find_public { + my ($server, $msg, $nick, $address, $targetchan) = @_; # Save all input to variables + my $find_channels = Irssi::settings_get_str('findbot_channels');# What channels to monitor + my $find_file = Irssi::settings_get_str('findbot_summaryfile'); # Filename which holds all the files + my $mp3list = Irssi::settings_get_str('findbot_sendlist'); # The nice list which is sent to users + my $max_results = Irssi::settings_get_int('findbot_maxresults');# Get max results retured to client + my $userqueuelimit = Irssi::settings_get_int('findbot_maxuserqueue'); # Get userqueue limit + my $serverqueuelimit = Irssi::settings_get_int('findbot_maxqueue'); # Get server maxqueue + my @checkchannels = split (/ /, $find_channels); # Split into an array + + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); # Get current time + + my $validchan = 0; + foreach my $singlechan ( @checkchannels ) { + if ( $singlechan eq $targetchan ) { + $validchan = 1; + } + } + # allows requesting and searching files in private messages because $targetchan has the own nickname in it when it is a private message, if not it's the channel where it was said + if ( $targetchan == "$server->{nick}" && user_is_in_active_channel($nick) ) { + $validchan = 1; + } + + if ( $validchan && Irssi::settings_get_bool('findbot_enabled') && timeslotenabled($wday,$hour,$min) ) { # Did the user say something in one of our channels? + my $mynick = $server->{nick}; + if ( $msg =~ /^\ *\@find\ +.+/i ) { # Was it a @find command? + $msg =~ s/^\ *\@find\ (.*)/$1/i; # Remove @find space spaces infront of it + $msg =~ tr/*/\ /; # Translate * to spaces + $msg =~ s/[\ \+]+/\.\*/g; # Translate ALL spaces to .* + $msg = sanitize_input($msg); + debugprint(10,"$nick is searching for $msg"); + my @matched; +# if ( length($msg) > 2 && $msg =~ m/[a-z]+/i) { # MUST be over 2 chars and contain atleast 1 or more normal characters + @matched = grep (/$msg/i,@bigarray); # Search for the matches +# } else { +# debugprint(10,"[ADMIN] $nick tried to search with too wide searchpattern ($msg)"); +# return; +# } + my $matchcount = 0; # Reset a counter + my $found_results = $#matched; # Return how many hits + $found_results++; # If nomatch then it is -1 + if ( $found_results > 0 ) { # Print number of results to the user + debugprint(10,"Found $found_results matches"); + $server->command("/QUOTE PRIVMSG " . $nick . " :Found $found_results matching files. Using: $IRSSI{name} v$VERSION for Irssi"); + } + foreach my $match (@matched) { # Loop through each file match + $match = strippath($match); # Remove the path and keep filename and mp3info + $match =~ s/:/\ \ \ :\ \ /; # Replace the ":" with " : " + if ( $matchcount < $max_results ) { # Is the matchlimit reached and is it a mp3 file? + $matchcount++; # Increase by one + $server->command("/QUOTE PRIVMSG " . $nick . " :!$mynick $match"); + } else { # Limit reached! + $server->command("/QUOTE PRIVMSG " . $nick . " :Resultlimit by " . $max_results . " reached. Download my list for more, by typing \@$server->{nick}"); + close (FINDFILE); + return; + } + } +# if ( $matchcount == 0 ) { +# $server->command("/QUOTE NOTICE " . $nick . " :No match found."); +# } + } elsif ( $msg =~ /^\ *!$server->{nick}.*/i ) { # Send file trigger + my $localsrvtag = $server->{tag}; # Get current servertag + debugprint(20,"$nick tries to queue $msg"); # Just debugoutput + $msg =~ s/\ *!$server->{nick}\ *(.*)/$1/; # Remove the trigger + $msg =~ tr/\(\)/\.\./; # Translate all () to . (any char) + $msg = sanitize_input($msg); + my @matched = grep (/$msg/i,@bigarray); # Get the real path from the file + if ( $matched[0] eq "" ) { + $server->command("/QUOTE NOTICE " . $nick . " :That file does not exist"); + return; + } + my $realfile = $matched[0]; # Append the real path to the relative path + $realfile =~ s/(.*)\ +:.*/$1/; # Remove : and beyoned + + my $scriptrequest = time() - $scriptdetect{$nick}; + if ( $scriptrequest <= $scriptdetecttime && $showscriptdetect ) { + debugprint(10,"[ADMIN] Requestscript detected on $nick"); + # return; # + } + chomp ($realfile); + if ( check_user_queued_items($nick,$localsrvtag) < $userqueuelimit ) { # Is it below allowed user queue limit + if ( already_queued_file($nick,$realfile,$localsrvtag) ) { + $server->command("/QUOTE PRIVMSG " . $nick . " :You have already queued that file!"); + } else { + my $priority = 1; # Default prio + if ( $lastqueuenumber < $serverqueuelimit ) { + foreach my $vchannel ($server->channels()) { # Loop through all joined channels + if ( $vchannel->{name} eq $targetchan ) { # Did he say it in a monitored channel + my $nickrec = $vchannel->nick_find($nick); + if ( $nickrec->{voice} ) { + $priority = 10; # A voiced user get 10 prioritypoints + } # Voiced user? + if ( $nickrec->{op} ) { + $priority = 20; # An op get 20 prioritypoints + } + last; # Skip rest of loop + } + } + add_file_to_queue($nick,$realfile,$localsrvtag,$priority); # Add file to queue + if ( Irssi::settings_get_bool('findbot_voicegetpriority') && $priority > 1 ) { + $server->command("/QUOTE PRIVMSG " . $nick . " :Added file to VIP queueposition $globalvippos."); + debugprint(10,"[ADMIN] $nick VIP queued: $realfile"); + } else { + $server->command("/QUOTE PRIVMSG " . $nick . " :Added file to queueposition $lastqueuenumber."); + debugprint(10,"[ADMIN] $nick queued: $realfile"); + } + } else { + $server->command("/QUOTE PRIVMSG " . $nick . " :The serverqueue is full. Please try again in a few minutes."); + debugprint(10,"[ADMIN] Queue is FULL."); + } + } + } else { # Tell the user the user queue limit is reached + $server->command("/QUOTE PRIVMSG " . $nick . " :You have reached the " . $userqueuelimit . " files queue limit."); + debugprint(10,"[ADMIN] $nick has reached his queuelimit"); + } + } elsif ( ($msg =~ /^\ *\@$server->{nick}-stats.*/i) || ($msg =~ /^\ *\@$server->{nick}-que.*/i) ) { + debugprint(10,"[ADMIN] $nick checked queuepositions"); + $server->command("/QUOTE PRIVMSG " . $nick . " :Sending you, your queuepositions"); + for ( my $i = 1; $i <= $lastqueuenumber; $i++ ) { # Loop through the queue + if ( $nickqueue{$i} eq $nick ) { + my $nicefile = nicefilename($filequeue{$i}); + $server->command("/QUOTE PRIVMSG " . $nick . " :Pos $i, $nicefile"); + } + } + } elsif ( $msg =~ /^\ *\@$server->{nick}-remove.*/i ) { + if ( $msg =~ /\ *\@$server->{nick}-remove\ *([\d]+)/ ) { # We have a number + my $qitem = $1; + debugprint(10,"[ADMIN] $nick is trying to remove queueposition $qitem"); + if ( $nickqueue{$qitem} eq $nick ) { # Check if the item is owned by the user + remove_queueitem($qitem); # Remove the requested queueitem + $server->command("/QUOTE NOTICE " . $nick . " :Item $qitem has"); + } else { # Unauthorized removal + debugprint(10,"[ADMIN] $nick tried to remove other peoples files from queue"); + $server->command("/QUOTE NOTICE " . $nick . " :You can't remove other peoples queueitems"); + } + } else { # We dont have a number, ie remove the whole user queue + debugprint(10,"[ADMIN] $nick has removed all own queueitems"); + for ( my $i = 1; $i <= $lastqueuenumber; $i++ ) { # Loop through the queue + if ( $nickqueue{$i} eq $nick ) { + remove_queueitem($i); + } + } + $server->command("/QUOTE NOTICE " . $nick . " :Your whole queue have been deleted"); + } + } elsif ( $msg =~ /^\ *\@$server->{nick}$/i ) { + if ( -r $mp3list ) { # Check if the file is still there + debugprint(10,"[ADMIN] $nick requested my list: $mp3list"); + $server->command("/QUOTE NOTICE " . $nick . " :Sending you my full list..."); + $server->command("/DCC SEND $nick $mp3list" ); + } else { + debugprint(5,"[WARNING] the $mp3list doesn't exist!"); + $server->command("/QUOTE NOTICE " . $nick . " :Something wicked happened. My list has disappeared and i have notified the bot owner."); + } + } elsif ( ($msg =~ /^\ *\@$server->{nick}\ *help\ *$/i) || ($msg =~ /^\ *\@$server->{nick}-help\ *$/i) ) { + debugprint(10,"[ADMIN] $nick requested HELP"); + $server->command("/QUOTE PRIVMSG " . $nick . " :Public channel commands:"); + $server->command("/QUOTE PRIVMSG " . $nick . " :\@find [searchpattern] : Searches my database for that file"); + $server->command("/QUOTE PRIVMSG " . $nick . " :!$server->{nick} [file] : Queues that file and it will be sent to you when its your turn"); + $server->command("/QUOTE PRIVMSG " . $nick . " :\@$server->{nick}-stats : Shows you your queuepositions"); + $server->command("/QUOTE PRIVMSG " . $nick . " :\@$server->{nick}-que : Shows you your queuepositions"); + $server->command("/QUOTE PRIVMSG " . $nick . " :\@$server->{nick}-remove : Clears all your queued files"); + $server->command("/QUOTE PRIVMSG " . $nick . " :\@$server->{nick}-remove 2 : Clear your queueposition 2"); + $server->command("/QUOTE PRIVMSG " . $nick . " :$IRSSI{name} v$VERSION $IRSSI{url}"); + } else { + return; # Just ordinary chatter + } + } + return; # Just in case +} + +sub check_vital_configuration { + my $configerror = 0; + if ( Irssi::settings_get_str('findbot_channels') eq "" ) { + $configerror = 1; + Irssi::print("The setting findbot_channels is empty."); + } elsif ( Irssi::settings_get_str('findbot_summaryfile') eq "" ) { + $configerror = 1; + Irssi::print("The setting findbot_summaryfile is empty."); + } elsif ( Irssi::settings_get_str('findbot_sendlist') eq "" ) { + $configerror = 1; + Irssi::print("The setting findbot_sendlist is empty."); + } elsif ( Irssi::settings_get_int('findbot_maxresults') == 0 ) { + $configerror = 1; + Irssi::print("The setting findbot_maxresults is empty."); + } elsif ( Irssi::settings_get_int('findbot_maxqueue') == 0 ) { + $configerror = 1; + Irssi::print("The setting findbot_maxqueue is empty."); + } elsif ( Irssi::settings_get_int('findbot_maxsends') == 0 ) { + $configerror = 1; + Irssi::print("The setting findbot_maxsends is empty."); + } elsif ( Irssi::settings_get_int('findbot_maxuserqueue') == 0 ) { + $configerror = 1; + Irssi::print("The setting findbot_maxuserqueue is empty."); + } elsif ( Irssi::settings_get_int('findbot_maxusersends') == 0 ) { + $configerror = 1; + Irssi::print("The setting findbot_maxusersends is empty."); + } elsif ( Irssi::settings_get_int('findbot_bannertime') == 0 ) { + $configerror = 1; + Irssi::print("The setting findbot_bannertime is empty."); + } + if ($configerror) { + Irssi::print("Please correct the settings first. The server will be disabled"); + Irssi::print("You have to reload the script when the settings are correct"); + Irssi::timeout_remove($timeout_tag); + Irssi::timeout_remove($banner_timeout); + } +} + +######## +# Main # +######## + +Irssi::settings_add_str("misc", "findbot_channels", ""); # Add a variable inside of irssi +Irssi::settings_add_str("misc", "findbot_summaryfile", ""); # Add a variable inside of irssi +Irssi::settings_add_int("misc", "findbot_maxresults", ""); # Add a variable inside of irssi +Irssi::settings_add_str("misc", "findbot_sendlist", ""); # Add a variable inside of irssi +Irssi::settings_add_int("misc", "findbot_maxqueue", ""); # Add a variable inside of irssi +Irssi::settings_add_int("misc", "findbot_maxsends", ""); # Add a variable inside of irssi +Irssi::settings_add_int("misc", "findbot_maxuserqueue", ""); # Add a variable inside of irssi +Irssi::settings_add_int("misc", "findbot_maxusersends", ""); # Add a variable inside of irssi +Irssi::settings_add_bool("misc", "findbot_showbanner", ""); # Add a variable inside of irssi +Irssi::settings_add_int("misc", "findbot_bannertime", ""); # Add a variable inside of irssi +Irssi::settings_add_bool("misc", "findbot_enabled", ""); # Add a variable inside of irssi +Irssi::settings_add_bool("misc", "findbot_voicegetpriority", ""); # Add a variable inside of irssi +Irssi::settings_add_int("misc", "findbot_minspeed", ""); # Add a variable inside of irssi +Irssi::settings_add_int("misc", "findbot_debuglevel", 10); # Add a variable inside of irssi +Irssi::settings_add_bool("misc", "findbot_mustbeinchannel", ""); +Irssi::settings_add_str("misc", "findbot_timeslots", ""); # Add a variable inside of irssi +Irssi::signal_add_last('message public', 'find_public'); # Hook up a function to public chatter +Irssi::signal_add_last('message private', 'find_public'); # Hook up a function to public chatter +Irssi::signal_add_last('dcc created', 'dcc_created'); # Hook when a dcc is created +Irssi::signal_add_last('dcc closed', 'dcc_closed'); # Hook when a dcc is closed +Irssi::signal_add_last('dcc destroyed', 'dcc_destroyed'); +Irssi::signal_add('nicklist changed', 'nickname_changed'); +Irssi::signal_add('message kick', 'user_got_kicked'); +Irssi::command_bind('findbotqueue', 'admin_showqueue'); +Irssi::command_bind('findbotremove', 'admin_removequeue'); +Irssi::command_bind('findbotreset', 'admin_reset'); +Irssi::command_bind('findbotreload', 'admin_reload'); +Irssi::command_bind('findbotactivesends', 'admin_activesends'); + +check_vital_configuration(); # Run a subroutine to check all variables before starting +if ( -r Irssi::settings_get_str('findbot_summaryfile') ) { + open (FINDFILE, "<", Irssi::settings_get_str('findbot_summaryfile')); # Open the file + @bigarray = <FINDFILE>; # Load it whole into memory :) + close (FINDFILE); +} else { + debugprint(10,"The Summaryfile cannot be read. Please check if the path is correct and the file is accually there."); +} +# my $slots_timeout = Irssi::timeout_add(600000, "send_ctcp_slots", ""); # Not implemented yet +$timeout_tag = Irssi::timeout_add(5000, "process_queue", ""); # Add a timeout value the process the queue +#my $bannertime = Irssi::settings_get_int('findbot_bannertime'); +#$banner_timeout = Irssi::timeout_add($bannertime * 1000, "print_banner", ""); # Set timeout for banner +Irssi::print("Findbot script v$VERSION by $IRSSI{'authors'} loaded!"); # Show version and stuff when it has been loaded + +if ( Irssi::settings_get_bool('findbot_enabled') ) { + Irssi::print("Findserver is Online"); +} else { + Irssi::print("Findserver is Offline"); +} +debugprint (5,"[ADMIN] Findbot fileserver has been loaded!"); + + +############################# +# INSTALLATION INSTRUCTIONS +############################# +# - Making of the "findbot_summaryfile" and "findbot_sendlist" +# Run the perlscript below to create the summaryfile and sendlist +# +# - Install it in Irssi +# Put the script in your Irssi scripts directory (~.irssi/scripts) +# Start Irssi and load it. (/run findbot.pl) +# Now start setting all vital variables by using the command /set +# set the "findbot_summaryfile" and "findbot_sendlist" to the files you just have created with +# the perlscript below. +# Dont forget to set all the other variables + + +####### Here is the script ######### + +# #!/usr/bin/perl +#use open ":encoding(UTF-8)"; +# if not supplied on cmd line this is the values +#@PATH = ("/mnt/folder1","/mnt/folder2"); # if only one folder should be used let it be @PATH = ("/mnt/folder1"); +#@INPUT = ""; +#$NICK = "nickname"; +#($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); +# +#$year = sprintf("%04d",$year+1900); +#$mon = sprintf("%02d",$mon + 1); +#$mday = sprintf("%02d",$mday); +#$DATE = "$year-$mon-$mday"; +#$LIST = $NICK . "_books_list.txt"; +#$CMD = $NICK . "_books_cmd.txt"; +#$CMD_7z = $NICK . "_books_cmd"; +#$padding = 50; # How many pad-characters should it be +#$use_file = 0; # each file is analysed by the program file if this is set to 0, this takes ages when with lots of files +#$use_compressed_cmdfile = 1; # if 1 then use 7z for compressing the command filelist that is being sent to the users +# +#if( "x" ne "x$ARGV[0]" ){ $NICK = $ARGV[0]; } +#if( "x" ne "x$ARGV[1]" ){ $PATH = $ARGV[1]; } +#if( "x" ne "x$ARGV[2]" ){ $LIST = $ARGV[2]; } +#if( "x" ne "x$ARGV[3]" ){ $CMD = $ARGV[3]; } +# +#print "Using nick: $NICK\n"; +#foreach (@PATH){ +# print "Finding under supplied path $_\n"; +# push(@INPUT,`find "$_" -follow -type f`); +#} +#print "Find done\n"; +#print "Summaryfile: $LIST\n"; +#print "Sendlist: $CMD\n"; +# +#print "Generating lists done/total files\n"; +#open(LIST,">$LIST"); +#open(CMD,">$CMD"); +# +#print LIST "### List generated: $DATE I have a total of $#INPUT files ###\n"; +#print CMD "### List generated: $DATE I have a total of $#INPUT files ###\r\n"; +#print CMD "### This list was created by Findbot for Irssi\r\n"; +#print CMD "### http://irssi.org/scripts\r\n"; +# +#$CHECKDIR=""; +#$CNT=0; +# +## arrays start 0 and If I have 10 mp3 without +1 it would stat you have 9 ... +#$TOTAL = $#INPUT + 1; +# +#sub padline { +# $filename = shift; +# $filelength = length($filename); +# $paddchar = "="; +# if ( $filelength <= $padding ) { +# for ( $counter = $filelength; $counter < $padding; $counter++ ) { +# $paddchar .= "="; +# } +# } +# return $paddchar; +#} +# +#foreach( @INPUT ){ +# $CNT++; +# print "\r$CNT/" . $TOTAL; +# chomp $_; +# +# $FILE=$_; +# $DIR=$_; +# $FILEwPATH=$_; +# +# $FILE =~ s/.*\/(.*)/$1/g; # only the file +# $DIR =~ s/(.*)\/.*/$1/g; # only the dir +# +# if ( $use_file ) { +# $STAT_OF_FILE = `file -b "$FILEwPATH"`; # the info about the file +# $STAT_OF_FILE =~ s#/##gio; # remove / +# chomp $STAT_OF_FILE; +# print LIST "$FILEwPATH : $STAT_OF_FILE\n"; # output to the LIST-file +# } else { +# print LIST "$FILEwPATH\n"; # output to the LIST-file +# } +# if( "$DIR" ne "$CHECKDIR" ){ +# # output to the CMD-file +# print CMD "\r\n=================================================\r\n"; +# $CHECKDIR = $DIR; print CMD "Files in $DIR\r\n"; +# print CMD "=================================================\r\n\r\n"; +# } +# if ( $use_file ) { +# print CMD "!$NICK $FILE " . padline($FILE) . " $STAT_OF_FILE\r\n"; # output to the CMD-file +# } else { +# print CMD "!$NICK $FILE\r\n"; # output to the CMD-file +# } +#} +#print CMD "EOF\r\n"; +#print LIST "EOF\r\n"; +#close LIST; +#close CMD; +#if ( $use_compressed_cmdfile ) { +# print "\ncompressing filelist...\n"; +# system "7z a -t7z -mx9 $CMD_7z.7z $CMD"; +#} +#print "\nList generation done\n"; |