#!/bin/perl 

#################################################################################
#                                                                               #
#    This file is part of GISMB.                                                #
#    GISMB Stands for 'GenEthic IRC Server Monitoring Bot'                      #
#                                                                               #
#    GISMB 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.             #
#                                                                               #
#    GISMB 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 GISMB; if not, write to the Free Software                       #
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  #
#                                                                               #
#################################################################################


########################################
## Name:    GenEthic
## Version: 1.0
## Author:  Pascal Gloor aka sPALe
## Date:    03.01.2002
########################################

# NOTHING SHOULD BE CHANGED IN THIS FILE

use IO::Socket;


# loading configuration file into variables

$path = $ARGV[0];

load_conf();

# testing if TCP connection is possible

$ircserver = IO::Socket::INET->new(
		PeerAddr   => $C{'CONN_DST_IP'},
		PeerPort   => $C{'CONN_DST_PORT'},
		Proto      => 'tcp',
		LocalAddr  => $C{'CONN_SRC_IP'}  ) || die "Check your config, TCP connection not possible";

# setting some time vars
$time{'old1'} = time;
$time{'old2'} = time;
$time{'old3'} = time;
$time{'old4'} = time;
$time{'old5'} = time;

# connecting to IRC Server and entering in main loop

while(<$ircserver>) {
	chop; chop;
	$line = $_;
#	if ( $line =~ /352/ ) { $do='nothing'; } else { print "IN  $line\n"; }

# getting time for this loop
	$time{'log'} = time;

# some special chars allowed in nicknames and text are substituted by others
# to be sure nothing bad can be done...

        $line =~ s/\[/\%20/g;
        $line =~ s/\]/\%21/g;
        $line =~ s/\|/\%22/g;
        $line =~ s/\^/\%23/g;
	$line =~ s/\`/\%24/g;

# stuff needed to connect

	if ( $first eq "" ) {
		if ( $C{'USER_PASS'} ne "" ) { quicksend("PASS $C{'USER_PASS'}"); }
		quicksend("USER $C{'USER_IDENT'} not_used not_used :$C{'USER_RNAME'}");
		quicksend("NICK $botnick");
		$first = "connected";
	}

# taking care to reply to PINGS

	if ( $line =~ /^PING / ) {
		$ping = $line;
		$ping =~ s/^PING /PONG /;
		quicksend("$ping");
	}

# in this part i manage 'time base event'
# that's why, having an Y line with 10 seconds
# pings is very important

	# lets do some stuff every X time, to get informations
	# from the server, around 20 seconds before i show
	# the stats..
	if ( $time{'log'}-$time{'old1'} > $C{'INFO_TIME'}-20 ) {
		ircsend("MAP");
		ircsend("STATS C");
		@HUBS = ''; $null = shift(@HUBS);
		@MAP = ''; $null = shift(@MAP);
		ircsend("LUSERS");
		ircsend("STATS u");
		$time{'old1'} = $time{'log'};
	}

	# lets show the stats and put them into logfile
	if ( $time{'log'}-$time{'old2'} > $C{'INFO_TIME'} ) {
		$mapcount = 0;
		foreach(reverse(sort(@MAP))) {
			($mapclient,$mapserver)=split(/:/);
			$mapcount++;
			if ( $mapserver =~ /^$C{'SERVER_NAME'}$/i ) {
				$mappos = $mapcount;
			}
		}
		if ( $oldchannels < 1 ) { $oldchannels = $channels; }
		$chandiff = $channels - $oldchannels;
		if (  $chandiff =~ /^[0-9]/ ) { $chandiff = "+$chandiff"; }
		$mapper = int(($locusers/($user1+$user2))*10000)/100;
		if ( $firstloop  eq "1" ) {
			ircsend("NOTICE $C{'CHAN_NAME'} :$locusers($mapper\%)/$users (+$usersmore2/-$usersless2 in $C{'INFO_TIME'} sec). No $mappos/$mapcount. $channels($chandiff)chans, ircu $ircduptime");
		}
		$oldchannels = $channels;

		#printing rping result
		$hubs = '';
		foreach(@HUBS) {
			$hubs = "$hubs $_:$rping{$_}";
		}
		$hubs =~ s/^ //;
		if ( $firstloop  eq "1" ) {
			ircsend("NOTICE $C{'CHAN_NAME'} :RPING-> $hubs");
		}
		# looking if we have to display some external data.
		if ( $C{'EXTERNAL_FILE'} ne "" ) {
			$ex_display = '';
			open(EXTERNAL,$C{'EXTERNAL_FILE'});
			while(<EXTERNAL>) {
				chop;
				($ex_name,$ex_opt,$ex_data)=split(/;/);
				if ( $ex_opt eq "ANY" ) {
					$ex_display = "$ex_display $ex_name:$ex_data";
				} elsif ( $ex_opt =~ /^[0-9]+$/ ) {
					if ( $ex_data > $ex_opt ) {
						$ex_display = "$ex_display $ex_name:$ex_data";
					}
				} elsif ( $ex_opt =~ /^\-[0-9]+$/ ) {
					$ex_opt =~ s/^.//;
					if ( $ex_data < $ex_opt ) {
						$ex_display = "$ex_display $ex_name:$ex_data";
					}
				}
			} close(EXTERNAL);
			$ex_display =~ s/^ //;

			if ( $ex_display ne "" && $firstloop eq "1" ) {
				ircsend("NOTICE $C{'CHAN_NAME'} :$ex_display");
			}
		}

		# this file can then be used to do some MRTG graphs or so...
		if ( $firstloop  eq "1" ) {
			open(LOG,">$path/var/genethic.log");
			$mapper = $mapper * 100;
			print LOG <<EOF;
LOCAL_USERS:$locusers
GLOBAL_USERS:$users
MAX_LOCAL_USERS:$maxusers
CHANNEL:$channels
POSITION:$mappos
USERS_PERCENT:$mapper
USERS_MORE:$usersmore2
USERS_LESS:$usersless2
EOF
			foreach(@HUBS) {
				print LOG "RPING_$_:$rping{$_}\n";
			}
			close(LOG);
		}

		$usersmore2 = 0;
		$usersless2 = 0;
		$time{'old1'} = $time{'log'};
		$time{'old2'} = $time{'log'};
		$firstloop = "1";
	}

# trying to handle all types of incomming messages :-P
# sort them, put them in vars,etc etc....

	$from=''; $type=''; $type2=''; $content=''; $nick='';$user='';$host='';$fullhost='';$msgsrc='';
	if ( $line =~ /^:/ ) {
		$line =~ s/^://g;
		$from = $line; $from =~ s/ .*//g;
		$type  = $line; $type =~ s/^$from //g; $type =~ s/ .*//g;
		$type2 = $line; $type2 =~ s/^$from $type //g; $type2 =~ s/ .*//g;
		if ( $type2 =~ /^:/ ) { $type2 = ''; }
		$content = $line; $content =~ s/^$from $type $type2.//g; $content =~ s/^://g;

		if ( $from =~ /\@/ && $from =~ /\!/ ) {
			$msgsrc = "user";
			($nick,$fullhost)=split(/\!/,$from);
			($user,$host)=split(/\@/,$fullhost);
		} else {
			$msgsrc = "server";
			$nick = "";
			$user = "";
			$host = "";
		}
	}

# lets check if you're not under floodbots attack :-) or any other mass (dis)connects...

        if ( $locusers ne "" && $oldlocusers eq "" ) { $oldlocusers = $locusers; $time{'lastusers'} = $time{'log'}; }

        $usersdiff = $locusers - $oldlocusers;
        $tdiff = $time{'log'} - $time{'lastusers'};
        if ( abs($usersdiff) >= $C{'USER_THRESHOLD'} && $tdiff >= $C{'TIME_THRESHOLD'} ) {
                if ( $usersdiff =~ /^[0-9]/ ) { $usersdiff = "+" . $usersdiff; }
                if ( abs($usersdiff/$tdiff)*100 >= $C{'USER_SEC_THRESHOLD'} ) {
			ircsend("NOTICE $C{'CHAN_NAME'} :WARNING Possible attack: $usersdiff (+$usersmore1/-$usersless1) users in $tdiff seconds ($locusers users)");
                } elsif ( $C{'PRINT_ONLY_WARNING'} ne "TRUE" ) {
                        ircsend("NOTICE $C{'CHAN_NAME'} :$usersdiff (+$usersmore1/-$usersless1) users in $tdiff seconds ($locusers users)");
                }
                $oldlocusers = $locusers;
                $time{'lastusers'} = $time{'log'};
		$usersmore1 = 0;
		$usersless1 = 0;
        }


# ok now, the big part, taking care of what to do with all this information....

	if ( $msgsrc eq "server" ) {
		# nickname already used, changing to next one
		if ( $type eq "433" ) {
			$botnick = shift(@NICKS);
			if ( $botnick eq '' ) {
				print STDERR "Fatal Error, no more nicknames available, change your config!\n";
				exit 1;
			}
#			print "changing nick to $botnick because: $line\n";
			quicksend("NICK $botnick");
		# Hey, i m connected now, lets do some stuff now..
		} elsif ( $type eq "001" ) {
			if ( $C{'X_AUTH'} eq "TRUE" ) {
				ircsend("PRIVMSG $C{'X_HOST'} :login $C{'X_USER'} $C{'X_PASS'}");
			}
			ircsend("OPER $C{'O_USER'} :$C{'O_PASS'}");
			ircsend("MODE $botnick +id");
			ircsend("MODE $botnick +s 32767");
			ircsend("JOIN $C{'CHAN_NAME'} :OVERRIDE");
			ircsend("MODE $C{'CHAN_NAME'} +o $botnick");
			if (  $C{'CHAN_KEEP_MODES'} eq "TRUE" ) {
				ircsend("MODE $C{'CHAN_NAME'} $C{'CHAN_MODES'}");
			}
		# STATS C Result
		} elsif ( $type eq "213" ) {
			($null,$null,$null,$uplink,$null,$null)=split(/ /,$content);
			$uplink =~ tr/[A-Z]/[a-z]/;
			push(@HUBS,"$uplink");
			$havehubs = "yes";

		# End of stats C
		} elsif ( $type eq "219" && $havehubs eq "yes" ) {
			foreach(@HUBS) {
				ircsend("RPING $_ :12345678");
			}
			$havehubs = "no";
		# end of WHO
		} elsif ( $type eq "315" ) {
			clientsend("NOTICE $clones_query :Users loaded, computing results...");

			$last = "FIRSTTIME";
			$count = 0;
			foreach(sort(@CUSER)) {
				if ( $last eq $_ || $last eq "FIRSTTIME" ) {
					$count++;
				} else {
					if ( $count > 10 ) {
						$count = "000$count"; $count =~ s/.*(....)$/$1/;
						push(@CRESULT,"$count\;user\@\;$last");
					}
					$count = 1;
				}
				$last = $_;
			}

                        $last = "FIRSTTIME";
			$count = 0;
                        foreach(sort(@CHOST)) {
                                if ( $last eq $_ || $last eq "FIRSTTIME" ) {
                                        $count++;
                                } else {
                                        if ( $count > 10 ) {
                                                $count = "000$count"; $count =~ s/.*(....)$/$1/;
                                                push(@CRESULT,"$count\;\@hostname\;$last");
                                        }
                                        $count = 1;
                                }
                                $last = $_;
                        }

                        $last = "FIRSTTIME";
			$count = 0;
                        foreach(sort(@CNAME)) {
                                if ( $last eq $_ || $last eq "FIRSTTIME" ) {
                                        $count++;
                                } else {
                                        if ( $count > 10 ) {
                                                $count = "000$count"; $count =~ s/.*(....)$/$1/;
                                                push(@CRESULT,"$count\;RealName\;$last");
                                        }
                                        $count = 1;
                                }
                                $last = $_;
                        }

			$count = 0;
			foreach(reverse(sort(@CRESULT))) {
				($ccount,$cname,$ctype)=split(/\;/,$_);
				if ( $count < 30 ) {
					$ccount = $ccount + 0;
					clientsend("NOTICE $clones_query :Found $ccount users with $cname equal to \"$ctype\"");
				}
				$count++;
			}
			clientsend("NOTICE $clones_query :End-of-Result");
			$clones_query = '';
			@CUSER='';
			@CHOST='';
			@CNAME='';
			@CRESULT='';

		# receiving WHO result, and working on it... fucking hard...
		} elsif ( $type eq "352" ) {
			($null,$cloneuser,$clonehost)=split(/ /,$content);
			$clonename = $content;
			$clonename =~ s/^.* :3 //;
			push(@CUSER,$cloneuser);
			push(@CHOST,$clonehost);
			push(@CNAME,$clonename);
			
		# getting list of users when entering in channel, whois'ing them
		} elsif (  $type eq "353" ) {
			$content =~ s/.*://g;
			$content =~ s/\@//g;
			foreach(split(/ /,$content)) { ircsend("WHOIS $_"); }
		# hey, i m sure this guy  is an oper
		} elsif ( $type eq "313" ) {
			if ( $content =~ /is an IRC Operator/ ) {
				$content =~ s/ .*//;
				$opers{$content} = 'yes';
			}
		# end of whois...humm.. perhaps an action to take
		} elsif ( $type eq "318" ) {
			$content  =~ s/ :.*//;
			if ( $C{'CHAN_OPER_ONLY'} eq "TRUE" ) {
				if ( $opers{$content} eq "yes" ) {
					clientsend("NOTICE $content :You are an authorized user. /NOTICE $botnick help");
					ircsend("MODE $C{'CHAN_NAME'} +o $content");
				} else {
					if ( $C{'CHAN_OPER_ACTION'} eq "KICK" ) {
						ircsend("KICK $C{'CHAN_NAME'} $content :$C{'CHAN_OPER_ACTION_REASON'}");
					} elsif ( $C{'CHAN_OPER_ACTION'} eq "KILL" ) {
						ircsend("KILL $content :$C{'CHAN_OPER_ACTION_REASON'}");
					}	
				}
			} else {
				ircsend("MODE $C{'CHAN_NAME'} -o $content");
				ircsend("MODE $C{'CHAN_NAME'} -v $content");
			}
		# Humm, i m receiving a MAP result, lets work on that
		} elsif ( $type eq "015" ) {
			$mapserver = $content;
			$mapserver =~ s/.*(-|:)//;
			$mapserver =~ s/ .*//;
			$mapclient = $content;
			$mapclient =~ s/.* %20/00000/;
			$mapclient =~ s/ .*//;
			$mapclient =~ s/^.*(......)$/$1/;
			if ( $mapclient >= $C{'MAP_THRESHOLD'} ) {
				push(@MAP,"$mapclient:$mapserver");
			}
		# LUSERS result
		} elsif ( $type eq "251" ) {
			($null,$null,$user1,$null,$null,$user2,$null,$null,$servers,$null)=split(/ /,$content);
			$users = $user1 + $user2;
		# get ircd uptime
		} elsif ( $type eq "242" ) {
			$ircduptime = $content;
			$ircduptime =~ s/^Server Up //;
		# get number of channels from LUSERS
		} elsif ( $type eq "254" ) {
			$channels = $content;
			$channels =~ s/ .*//;
		# get number of local users from LUSERS
		} elsif ( $type eq "255" ) {
			$locusers = $content;
			$locusers =~ s/I have (.*) clients.*/$1/;
		# RPONG RESULT
		} elsif ( $type eq "RPONG" ) {
			($rpongserv,$rpongtime)=split(/ /,$content);
			$rpongserv =~ tr/[A-Z]/[a-z]/;
			$rping{$rpongserv} = $rpongtime;
		# channel modes changes
		} elsif ( $type eq "MODE" && $type2 =~ /^$C{'CHAN_NAME'}$/i ) {
			ircsend("MODE $C{'CHAN_NAME'} $C{'CHAN_MODES'}");
		# and now some server notices...
		} elsif ( $type eq "NOTICE" ) {
			# max users..
			if ( $content =~ /^Highest connection count/ ) {
				$maxusers = $content;
				$maxusers =~ s/.*\((.*) clients\)/$1/;
				if ( $maxusers > $oldmaxusers ) {
					ircsend("MODE $C{'CHAN_NAME'} +l $maxusers");
				}
				$oldmaxusers = $maxusers;
			# connecting users
			} elsif ( $content =~ /\*\*\* Notice -- Client connecting: / ) {
				$locusers++;
				$usersmore1++;
				$usersmore2++;

			# disconnecting users
			} elsif ( $content =~ /\*\*\* Notice -- Client exiting: / ) {
				$locusers--;
				$usersless1++;
				$usersless2++;
			} elsif ( $content =~ /\*\*\* Notice -- Failed OPER attempt by / && $C{'OPER_FAIL_CHECK'} eq "TRUE" ) {
				$content =~ s/.*Failed OPER attempt by //;
				$content =~ s/\(|\)//g;
				($opernick,$operhost)=split(/ /,$content);
				$operfail{$operhost}++;
				if ( $C{'OPER_FAIL_MAX'} <= $operfail{$operhost} ) {
					if ( $C{'OPER_FAIL_ACTION'} eq "KILL" ) {
						ircsend("KILL $opernick :$C{'OPER_FAIL_ACTION_REASON'}");
					} elsif ( $C{'OPER_FAIL_ACTION'} eq "LGLINE" ) {
						ircsend("GLINE $operhost $C{'OPER_FAIL_GLINE_TIME'} :$C{'OPER_FAIL_ACTION_REASON'} (banned for $C{'OPER_FAIL_GLINE_TIME'} seconds)");
					}
					ircsend("NOTICE $C{'CHAN_NAME'} :MAX OPER Fail by $opernick\!$operhost ($C{'OPER_FAIL_ACTION'})");
					$operfail{$operhost}=0;
				} else {
					ircsend("NOTICE $opernick :$C{'OPER_FAIL_WARNING'}");
					ircsend("NOTICE $C{'CHAN_NAME'} :OPER Fail by $opernick\!$operhost");
				}
			} elsif ( $content =~ /\*\*\* Notice -- Net break: / ) {
				$content =~ s/.*\*\*\* Notice -- Net break: //;
				ircsend("NOTICE $C{'CHAN_NAME'} :SPLIT: $content");
			} elsif ( $content =~ /\*\*\* Notice -- Net junction: / ) {
				$content =~ s/.*\*\*\* Notice -- Net junction: //;
				ircsend("NOTICE $C{'CHAN_NAME'} :JOIN: $content");
			} elsif (  $content =~ / is now operator / ) {
				$content =~ s/.*Notice -- //;
				($opernick,$operhost,$null,$null,$null,$opertype)=split(/ /,$content);
				$operhost =~ s/\(|\)//g;
				if ( $opertype eq "(o)" ) { $opertype = "LocalOPER"; } else { $opertype = "GlobalOPER"; }
				ircsend("NOTICE $C{'CHAN_NAME'} :$opernick\!$operhost is now $opertype");
			}
		}
	} elsif ( $msgsrc eq "user" && $nick ne $botnick ) {
		# hey, a guy is joining, but who is he?
		if ( $type eq "JOIN" ) {
			ircsend("WHOIS $nick");
			if ( $C{'X_AUTH'} eq "TRUE" ) {
				ircsend("PRIVMSG $C{'X_NICK'} :VERIFY $nick");
			}
		#  that guy is leaving, unauthing...
		} elsif ( $type eq "PART" || $type eq "QUIT" ) {
			$opers{$nick} = '';
		# Detecting authenticated users nick change.
		} elsif ( $type eq "NICK" ) {
			if ( $opers{$nick} eq "yes" ) {
				$opers{$nick} = '';
				$opers{$content} = "yes";
				ircsend("NOTICE $C{'CHAN_NAME'} :Nick change detected, $nick -> $content");
			}
		# CSBot has information for me ;-) lets share that...
		} elsif (  $type eq "NOTICE" && $nick eq "$C{'X_NICK'}" ) {
			ircsend("NOTICE $C{'CHAN_NAME'} :From $nick: $content");
		# yes, a guy is talking to me ;p
		} elsif (( $type eq "PRIVMSG" || $type eq "NOTICE" ) && $opers{$nick} eq "yes" ) {
			# lets manage common CTCP replies
			if ( $content =~ // ) {
				$content =~ s/^.(.*).$/$1/;
				if (  $content =~ /^PING / ) {
					ircsend("NOTICE $nick :$content");
				} elsif ( $content =~ /^VERSION/ && $C{'VERSION'} ne '' ) {
                                	ircsend("NOTICE $nick :VERSION $C{'VERSION'}");
                        	} elsif ( $content =~ /^TIME/ ) {
                                	ircsend("NOTICE $nick :TIME $time{'log'}");
                        	} elsif ( $content =~ /^FINGER/ && $C{'FINGER'} ne '' ) {
                                	ircsend("NOTICE $nick :FINGER $C{'FINGER'}");
                        	}
			# lets give him sime help as requested..
			} elsif (  $content =~ /^help$/i ) {
				$totalhelp ='';
				foreach(@HELP) {
					($hindex,$hdetail)=split(/\;/);
					$totalhelp = "$totalhelp $hindex";
				}
				$totalhelp =~ s/^ //;
				clientsend("NOTICE $nick :HELP INDEX: $totalhelp");
				clientsend("NOTICE $nick :Try /notice $botnick help <command>");
			# or detailed help
			} elsif (  $content =~ /^help /i ) {
				foreach(@HELP) {
					($hindex,$hdetail)=split(/\;/);
					if ( $content =~ /^help $hindex$/i || $content =~ /^help all$/i ) {
						$hdetail =~ s/^ *//;
						clientsend("NOTICE $nick :$hdetail");
					}
				}
			# the user want to reload my config
			} elsif ( $content =~ /^reload$/i ) {
				load_conf();
				clientsend("NOTICE $nick :Config files reloaded...");
			# the user want me to change nickname
			} elsif (  $content =~ /^nick /i ) {
				$content =~ s/^nick //i;
				ircsend("NICK $content");
			# let the user send some RAW commands
			# can be userfull for debugging, or others?
			} elsif ( $content =~ /^raw /i ) {
				$content =~ s/^raw //i;
				ircsend("$content");
			# wanna talk  in the channel?
			} elsif ( $content =~ /^chan /i ) {
				$content =~ s/^chan //i;
				ircsend("PRIVMSG $C{'CHAN_NAME'} :$content");
			# how to suicide ;)
			} elsif ( $content =~ /^quit /i ) {
				$content =~ s/^quit /quit :/i;
				ircsend("NOTICE $C{'CHAN_NAME'} :Quitting, requested by $nick");
				ircsend("$content");
			# lets see if see some clones around
			} elsif ( $content =~ /^clones/i ) {
				if (  $clones_query ne '' ) {
					clientsend("NOTICE $nick :$clones_query is already detecting clones. please wait until (s)he is finished");
				} else {
					$clones_query = $nick;
					clientsend("NOTICE $nick :Getting users list and detecting clones...");
					ircsend("WHO $C{'SERVER_NAME'} x");
				}

			# humm... showing the map can be huge, the user is the king, let do.
			} elsif ( $content =~ /^map$/i ) {
				clientsend("NOTICE $nick :Network MAP ordered by users");
				$counter = 0;
				foreach(reverse(sort(@MAP))) {
					($mapuser,$mapserv)=split(/:/);
					$counter++;
					$counter = "00$counter"; $counter =~ s/.*(..)$/$1/;
					if ( $mapserv =~ /^$C{'SERVER_NAME'}$/i ) {
						clientsend("NOTICE $nick :$counter($mapuser) $mapserv");
					} else {
						clientsend("NOTICE $nick :$counter($mapuser) $mapserv");
					}
				}
				clientsend("NOTICE $nick :End of MAP");
			}
		}
	} elsif ( $nick eq $botnick ) {
		# but why should i change my own nickname? who knows...
		if ( $type eq "NICK" ) {
			$botnick = $content;
		}
	}
	checktosend();
}

# SUB to manage the outgoing messages queue
# and to slow it down if needed, to avoid
# Excess_flood disconnects..

sub clientsend {
        $msg4srv = shift;
        $msg4srv =~ s/\%20/\[/g;
        $msg4srv =~ s/\%21/\]/g;
        $msg4srv =~ s/\%22/\|/g;
        $msg4srv =~ s/\%23/\^/g;
        $msg4srv =~ s/\%24/\`/g;

#       print "DEBUG: Pushed msg \"$msg4srv\" to queue\n";
        if ( $C{'OPS_INFO_ONLY'} eq "TRUE" || $C{'CHAN_OPER_ONLY'} ne "TRUE" ) {
                $msg4srv =~ s/^NOTICE $C{'CHAN_NAME'} :/NOTICE \@$C{'CHAN_NAME'} :/;
        }
	push(@TOSEND2,"$msg4srv");
}

sub ircsend {
	$msg4srv = shift;
	$msg4srv =~ s/\%20/\[/g;
	$msg4srv =~ s/\%21/\]/g;
	$msg4srv =~ s/\%22/\|/g;
	$msg4srv =~ s/\%23/\^/g;
	$msg4srv =~ s/\%24/\`/g;

#	print "DEBUG: Pushed msg \"$msg4srv\" to queue\n";
	if ( $C{'OPS_INFO_ONLY'} eq "TRUE" || $C{'CHAN_OPER_ONLY'} ne "TRUE" ) {
		$msg4srv =~ s/^NOTICE $C{'CHAN_NAME'} :/NOTICE \@$C{'CHAN_NAME'} :/;
	}
	push(@TOSEND,"$msg4srv");
}

sub checktosend {
	$qcount=0;
	$qcount2 = 0;
	foreach(@TOSEND) { $qcount++; }
	foreach(@TOSEND2) { $qcount2++; }
#	if ( $qcount2 > 0 ) { print "DEBUG: Queue2 has $qcount2 msgs waiting\n"; }
#	if ( $qcount > 0 ) { print "DEBUG: Queue has $qcount msgs waiting\n"; }
	if ( $msgcount eq '' ) { $msgcount = 1; }
	if ( $time{'log'}-$time{'old3'} >= $msgcount ) {
		$msgcount = 1;
		if ( $qcount > 1 ) {
			for($loop=0; $loop<4; $loop++ ) {
				$tosend=shift(@TOSEND);
				if ( $tosend ne '' ) {
					$msgcount++;
					print $ircserver "$tosend\n";
#					print "OUT $tosend\n";
				}	
			}
		} else {
                        for($loop=0; $loop<4; $loop++ ) {
                                $tosend=shift(@TOSEND2);
                                if ( $tosend ne '' ) {
                                        $msgcount++;
                                        print $ircserver "$tosend\n";
#                                        print "OUT $tosend\n";
                                }
                        }
		}
	$time{'old3'} = $time{'log'};
	}
}

# SUB to manage the URGENT outgoing messages
# Should ONLY be used for server PING replies
# had to do it, cause if the outqueue is full
# the ping reply to the server  may take a while
# and the bot disconnects ;(

sub quicksend {
	$text_to_send = shift;
	print $ircserver "$text_to_send\n";
#	print "OUT $text_to_send\n";
}

# SUB For loading/reloading the config file
# be carefull, an error in config may the bot STOP running

sub load_conf {

	open(CONF,"$path/etc/genethic.conf") || die "$path/etc/genethic.conf not found";
	while(<CONF>) {
		chop;
       		 if ( $_ =~  /^[A-Z]+/ ) {
			($name,$value)=split(/:/);
			$C{$name} = $value;
			print "CONFIG: $name = \"$value\"\n";
		}
	} close(CONF);

	@HELP=''; $null = shift(@HELP);
	open(HELP,"$path/etc/help.txt") || die "$path/etc/help.txt not found";
	while(<HELP>) { chop; push(@HELP,$_); } close(HELP);

	foreach(split(/ /,$C{'NICKS'})) {
		push(@NICKS,$_);
	}

	if ( $first eq "" ) {
		$botnick = shift(@NICKS);
	}

	# checking some stuff in config, hope you configured correctly ;p

	if ( $C{'CONN_DST_IP'} =~ /^[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$/ ) { null; } else { print STDERR "CONN_DST_IP error\n"; $err++; }
	if ( $C{'CONN_DST_PORT'} < 1 || $C{'CONN_DST_PORT'} > 65535 ) { print STDERR "CONN_DST_PORT error\n"; $err++; }
	if ( $C{'CONN_SRC_IP'} =~ /^[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$/ ) { null; } else { print STDERR "CONN_SRC_IP error\n"; $err++; }
	if ( $C{'USER_IDENT'} eq "" ) { print STDERR "USER_IDENT error\n"; $err++; }
	if ( $C{'USER_RNAME'} eq "" ) { print STDERR "USER_RNAME error\n"; $err++; }
	if ( $C{'NICKS'} eq "" ) { print STDERR "NICKS error\n"; $err++; }
	if ( $C{'X_AUTH'} != /^(TRUE|FALSE)$/ ) {  print STDERR "X_AUTH error\n"; $err++; }
	if ( $C{'O_USER'} eq "" ) { print STDERR "O_USER error\n"; $err++; }
	if ( $C{'O_PASS'} eq "" ) { print STDERR "O_PASS error\n"; $err++; }
	if ( $C{'CHAN_NAME'} != /^\&/ ) { print STDERR "CHAN_NAME error\n";  $err++; }
	if ( $C{'CHAN_KEEP_MODES'} != /^(TRUE|FALSE)$/ ) {  print STDERR "CHAN_KEEP_MODES error\n";  $err++; }
	if ( $C{'CHAN_OPER_ONLY'} != /^(TRUE|FALSE)$/ ) {  print STDERR "CHAN_OPER_ONLY error\n";  $err++; }

	if (  $err >= 1 ) {
		if ( $first eq "" ) {
			print STDERR "$err errors found in configuration!\n";
			print STDERR "Please check your config file\n";
			exit 1;
		} else {
			ircsend("NOTICE $nick :!!!WARNING!!! at least $err errors found in configuration file");
			ircsend("NOTICE $nick :I will now have to quit, sorry ;-(");
			ircsend("QUIT :Configuration error");
		}
	}
}
