All pastes #1414963 Raw Edit

eeeee

public text v1 · immutable
#1414963 ·published 2009-05-07 03:24 UTC
rendered paste body
### NOTE: Bot is optomised for Quakenet, using their AUTH system.
### It may in fact fail to work on other networks

use strict;
use IO::Socket;
use Switch;
use LWP::UserAgent;

# Pointless info hash, wooo!
my %info = (
	Version => "0.2b",
	Author => "Erasmus, with much help from Al",
	Description => "A basic IRC bot with a few functions"
);

# Variables to control some parts of the script. Most of these are pretty obvious.
my $channel_rejoin	= 1;
my $kick_retaliate	= 1; # This one doesn't work, and I'm not sure why.
my $invite_respond	= 1;
my $quoting		= 1; # Sets the logging of new quotes, !quote will be available even if this is set to 0

# The server to connect to and various connect details.
my $server = "irc.quakenet.org";
my $mynick = "eeeee";
my $login = "eeeee";

# A message commands hash. A hash of commands that can be contained in messages, as you may guess.
my %msgcommands = (
	qr/^!tea$/ =>		'unprotected_command("tea",$who{Nick},$target)',
	qr/^!tea (.+$)/ =>	'unprotected_command("teafoo",$who{Nick},$target,$params)',
	qr/^!grue$/ =>		'unprotected_command("grue",$who{Nick},$target)',
	qr/^!grue (.+$)/ =>	'unprotected_command("gruefoo",$who{Nick},$target,$params)',
	qr/(\W|^)life(\W|$)/ =>	'unprotected_command("life",$who{Nick},$target)',
	qr/^!g (.+$)/ =>	'unprotected_command("google",$who{Nick},$target,$params)',
	qr/^die$/ =>		'protected_command("die",$who{Nick},$target)',
	qr/^!insult (.+$)/ =>	'unprotected_command("insult",$who{nick},$target,$params)',
	qr/^hai2u, $mynick/ =>	'unprotected_command("hai", $who{nick},$target)',
	qr/^!topic (\S+$)/ =>	'unprotected_command("get_topic",$who{nick},$target,$params)'
);

# A part commands hash. Similar to %msgcommands but with PART not PRIVMSG
my %partcommands = (
	qr/^aaaarrrrghh\!\!\! \*crunch\*$/ =>	'unprotected_command("crunch",$who{Nick},$target)'
);

# The channel(s) which the bot will join.
my @channels = qw(#rtere);

# Channel hash with one example channel. The channel hash is as yet unimplemented in any meaningful way.
my %channels = (

	'#falsechannel' => (
		users => 3,
		nicklist => qw(foo bar baz),
		modes => qw(t m n),
		status => 'operator',
		topic => 'Yaaah'
	)

);

# Individuals hash that tracks users
my %individuals = (
	
	'false!user@somewhere.lol' => (
		channels => qw(#falsechannel),
		auth => 'bleh',
		nick => 'foobarface'
	)
);
		

# List of trusted auths
my @trusted = qw(
	Erasmu1
	Shiyiya
);

# Connect to the IRC server.
my $sock = new IO::Socket::INET(PeerAddr => $server, PeerPort => 6667, Proto => 'tcp') or die "Can't connect!\n";

# Log on to the server.
print $sock "NICK $mynick\r\n";
print $sock "USER $login 8 * :eeeee, the once and future bot!\r\n";

# Keep reading lines from the server.
while (my $input = <$sock>) {
	
	
	# Parsing (such as it is)
	$input =~ s/\r\n//g;
	my @stream = split(' ',$input,4);
	
	# Print input to console
	print "$input\n";
	
	###
	### @stream[0] contains info on who sent the data (*!*@* format) and PING if it's a ping.
	### @stream[1] contains number code [001 is just connected code] or message type (such as PRIVMSG)
	### @stream[2] holds the target of the message, so generally either a channel name or the bot's nick.
	### @stream[3] contains any other things, such as messages and whatnot.
	###
	
	# Deal with PINGs
	if (@stream[0] eq "PING") {
		print $sock "PONG @stream[1]\r\n";
		print "PING answered.\n";
	}
  
  	# Change my nick if some cunt has stolen it.
  	if (@stream[1] eq "433") {
  		$mynick = $mynick."e";
  		print $sock "NICK $mynick\r\n";
 	}
 	
  	# Join channels and other just-connected-things
  	if (@stream[1] eq "001") {
  		print "Connected!\n";
  		
  		# Join the channels
  		map { print $sock "JOIN $_\r\n" } @channels;
  		
  		# Quakenet AUTH /msg Q@CServe.quakenet.org AUTH I-R-A-RBOT A3kFmuoN7P, and add Qnet hostmask
  		action ("message","Q\@CServe.quakenet.org","AUTH I-R-A-RBOT A3kFmuoN7P");
  		action ("selfmode", "+x");
  	}
  	
  	# Grab channel data and basic user data:
  	# First, get the topic for all channels
  	if (@stream[1] eq "332") {
  		my @t = split(' :',@stream[3],2);
  		$channels{$t[0]}{topic} = $t[1];
  	}
  	# Then, get the userlists
  	if (@stream[1] eq "353") {
  		my @t = split(' ',@stream[3]);
  		my $chan_list = $t[1];
  		splice (@t, 0, 3);
  		foreach my $r (@t) {
  		
  			#push ($channels{$chan_list}{nicklist}, $r);
  			$individuals{known} = 1;
  			#push ($individuals{$r}{channels}, $chan_list);
  		}
  	}
  		
  	
  	# A little bit of parsing...
  	@stream[0] =~ s/://;
  	my %who = host_parse(@stream[0]);
  	my $target = @stream[2];
  	@stream[3] =~ s/://;  	
  	
  	# Message commands
  	if (@stream[1] eq "PRIVMSG") {
  	
  		my @catches = grep { @stream[3] =~ $_ } keys %msgcommands;
  		my $params = (@stream[3] =~ @catches[0])[0];
		## print "\n\n\nP: $params\n\n\n";
		
		if(scalar @catches) {
			my $eval = $msgcommands{$catches[0]};
			eval $eval;
		}
  	}
  	
  	if (@stream[1] eq "PART") {
  	
  		my @catches = grep { @stream[3] =~ $_ } keys %partcommands;
		my $params = (@stream[3] =~ @catches[0])[0];
  		
  		if(scalar @catches) {
			my $eval = $partcommands{$catches[0]};
			eval $eval;
		}
	}
		
		
  	
  	# I have been kicked, ohno!
  	if (@stream[1] eq "KICK" && @stream[3] =~ /^$mynick/) {
  	
  		# If we're allowed, rejoin.
  		if ($channel_rejoin) {
  			action("join",@stream[2]);
  		}
  		
  		# If we're allowed, kick the fucker.
  		if ($kick_retaliate) {
  			sleep 2;
  			action("kick",@stream[2],"$who{Nick} :NO U!");
  		}
  	}
  	
  	# I have been invited, YAY!
  	if (@stream[1] eq "INVITE") {
  		
  		# If we're allowed, join and say hi.
  		if ($invite_respond) {
  			action("join",@stream[3]);
  			action("action",@stream[3],"sits on ".$who{Nick});
  		}
  	}
  }
  
  # Unprotected commands
  sub unprotected_command {
  	
  	my ($command, $nick, $target, $param) = @_;
  	
  	if ($command eq "tea") { action ("action",$target,"pours tea on $nick"); }
  	
  	if ($command eq "teafoo") { action ("action",$target,"pours tea on $param"); }
  	
  	if ($command eq "grue") { 
  		my @nicklist = nick_list($target);
  		action ("message",$target,@nicklist[int(rand()*scalar(@nicklist))]." was eaten by a grue!"); 
  	}
  	
  	if ($command eq "gruefoo") { action ("message",$target,"$param was eaten by a grue!"); }
  	
  	if ($command eq "life") { action ("message",$target,"Life. Don't talk to me about life."); }
  	
  	if ($command eq "google") {
		my @results = google($param);
  		map { action ("message",$target,$_) } @results ;
  	}
  	
  	if ($command eq "insult") {
  		my $insult = make_insult();
  		action ("message",$target,$param.", ".$insult."!");
  	}
  	
  	if ($command eq "crunch" && lc($nick) eq "vurl") {
  		action ("message",$target,"Oh no! Vurl, come back!");
  		sleep 2;
  		action ("invite","vurl",$target);
  	}
  	
  	if ($command eq "hai" && lc($nick) eq "vurl") {
  		print "\n\n\n\n\n\n\n\n\n\n\n\n";
  		action ("message",$target,"hai2u, vurl! ^_^");
  	}
  	
  	if ($command eq "get_topic") {
  		action ("message",$target,"topic is ".$channels{$target}{topic});
  	}
  }
  
  # Protected commands
  sub protected_command {
  	
  	my ($command, $nick, $target, $param) = @_;
  	
  	
  	my $auth = auth($nick);
  	
  	my $access = scalar grep {$_ eq $auth} @trusted;
  	
  	if (!$access) { return 0; }
  	
  	if ($command eq "die") { action ("message",$target,"Ouch!"); exit "im ded"; }
  	
  }
  
  
  # Retrieves a list of people on a channel.
  sub nick_list {
  
  	my $channel = shift;
  	
  	# Send a request to the server and retrieve the reply.
  	print $sock "NAMES $channel\r\n";
  	my $names = <$sock>;
  	
  	# Oh good, more parsing.
  	$names =~ s/\r\n//g;
  	$names =~ s/(.*):(.*):(.*)/\3/;
  	$names =~ s/@//g;
  	
  	# Print names to console for good measure.
  	print $names."\n";
  	
  	# Split and return
  	my @list = split (" ",$names);
  	return @list;
  }
  
  
  # Parses a host of format foo!bar@baz into a hash.
  sub host_parse {
  
  	
  	# Parse, parse, parse...
  	my $host = shift;
  	$host =~ /(.+)\!(.+)\@(.+)/;
  	
  	
  	# Stick the result in a hash, for ease of access
  	my %parsed_host = (
  		Nick => $1,
  		Ident => $2,
  		Host => $3
  	);
  	
  	# Return the hash
  	return %parsed_host;
  	
  }
  
  # Gets some whois info on a nickname and parses it to something vaguely readable.
  sub whois {
  
  	my $nick = shift;
  	print "\n\nwhois invoked\n\n";
  	
  	# Send a request to the server and retrieve the reply.
  	print $sock "WHOIS $nick\r\n";
	my $whois = <$sock>;
  	
  	#Print to console
  	print "\n".$whois."\n\n";
  	
  	# DJ... parse dat shit!
  	$whois =~ s/\r\n//g;
  	$whois =~ s/://g;
  	
  	# If nickname does no exist return 0
  	if ($whois =~ /401.*No such nick/) {
  		return 0;
  	}
  	
  	# Extract me some variables
  	my ($ident, $vhost) = ( $whois =~ /311 .* .* (.*) (.*) \*/ );
  	my $host = $nick."!".$ident."@".$vhost;
  	
  	return $host;
  }
  
  # Streamlines sending messages to the server
  sub action {
  
  	my ($action_type, $location, $parameters) = @_;

	my $action;
  	
  	# Work out exactly what we need to send to the server
  	switch (lc($action_type)) {
  		case "message"		{ $action = "PRIVMSG $location :$parameters\r\n" }
  		case "action"		{ $action = "PRIVMSG $location :\001ACTION $parameters \001\r\n" }
  		case "join"		{ $action = "JOIN $location\r\n" }
  		case "part"		{ $action = "PART $location\r\n" }
  		case "invite"		{ $action = "INVITE $location $parameters\r\n" }
  		case "kick"		{ $action = "KICK $location $parameters\r\n" }
  		case "selfmode"		{ $action = "MODE $mynick $location\r\n" }
  		else			{ return 0; }
  	}
  	
  	# Send it and return. No additional parsing required.
  	print $sock $action;
  	return 1;
  }
  		
  # Queries google and parses the result
  sub google {
  	
  	my $search = shift;
  	$search =~ s/\s/+/g;
  	  	
  	# Get the page (I really, really don't understand this chunk o' code)			
	my $ua = new LWP::UserAgent;
	$ua->agent("AgentName/0.1 " . $ua->agent);
  	my $req = new HTTP::Request GET => "http://www.google.com/search?hl=en&q=$search";	
	my $res = $ua->request($req);
     	my $content = $res->content;
     	
     	# Some horrific parsing
     	$content =~ s/\"http:\/\/.*?(google\.com).*?\"//g;
     	my @s = ($content =~ /\"(http:\/\/.*?)\"/g);
     	
     	my @results;
     	
     	# Remove google cache urls in a rather clumsy manner.
     	foreach my $url (@s) {
     		if ($url !~ /cache/) {
     			push @results, $url;
     		}
     	}     	
     	
     	# splice to three results
     	splice (@results,3);
     	
     	#Return
     	return @results
     
   }
     
   # Finds out if someone is auth'd
   sub auth {
     	my $nick = shift;
	print "\n\nwhois invoked on $nick\n\n";
	  	
	# Send a request to the server and retrieve the reply.
	print $sock "WHOIS $nick\r\n";
	  	
	my $whois;
	while (<$sock>) {
			
		$whois = <$sock>;
		
		#Print to console
	  	#print "\n".$whois."\n\n";
	  		
	  	# Some parsing that I don't think is needed, but can't be bothered to test
	  	$whois =~ s/\r\n//g;
	  	print "\n".$whois."\n";
	  	
	  	# If nickname does no exist return 0
	  	if ($whois =~ /401.*No such nick|End of \/WHOIS/) {
	  		return 0;
	  	}
	  	
	  	# Find the auth and return it
	  	if ($whois =~ /330 .* (.+?) :is/) {
	  		my $auth = $1;
	  		print "found:: $auth\n\n";
	  		return $auth;
	  	}
	}
	
	# Return 0 if not auth'd
  	return 0;
  }
  
  # Sub for the insult command
  sub make_insult {
  	my @one = qw(
  	
  		artless bawdy beslubbering bootless churlish cockered clouted craven currish dankish dissembling droning errant fawning
		fobbing froward frothy gleeking goatish gorbellied impertinent infectious jarring loggerheaded lumpish mammering mangled
		mewling paunchy pribbling puking puny qualling rank reeky roguish ruttish saucy spleeny spongy surly tottering unmuzzled
		vain venomed villainous warped wayward weedy yeasty
		
	);
	
	my @two = qw(
	
		base-court bat-fowling beef-witted beetle-headed boil-brained clapper-clawed clay-brained common-kissing crook-pated
		dismal-dreaming dizzy-eyed doghearted dread-bolted earth-vexing elf-skinned fat-kidneyed fen-sucked flap-mouthed fly-bitten
		folly-fallen fool-born full-gorged guts-griping half-faced hasty-witted hedge-born hell-hated idle-headed ill-breeding
		ill-nurtured knotty-pated milk-livered motley-minded onion-eyed plume-plucked pottle-deep pox-marked reeling-ripe
		rough-hewn rude-growing rump-fed shard-borne sheep-biting spur-galled swag-bellied tardy-gaited tickle-brained toad-spotted 
		unchin-snouted weather-bitten
		
	);
	
	my @three = qw(
	
		apple-john baggage barnacle bladder boar-pig bugbear bum-bailey canker-blossom clack-dish clotpole coxcomb codpiece death-token 
		dewberry flap-dragon flax-wench flirt-gill foot-licker fustilarian giglet gudgeon haggard harpy hedge-pig horn-beast
		hugger-mugger joithead lewdster lout maggot-pie malt-worm mammet measle minnow miscreant moldwarp mumble-news nut-hook
		pigeon-egg pignut puttock pumpion ratsbane scut skainsmate strumpet varlot vassal whey-face wagtail
	);
	
	my $partone = @one[int(rand()*scalar(@one))];
	my $parttwo = @two[int(rand()*scalar(@two))];
	my $partthree = @three[int(rand()*scalar(@three))];
	
	return "thou ".$partone." ".$parttwo." ".$partthree;
}