############################################################################### # 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. # @-stats : Replies with the users queue. # @-remove : Will remove the users whole queue # @-remove 2 : Will remove queue position 2 from the queue # @-help : Will message the help to the user. # ! :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 = ; # 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 = ; # 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";