import socket, argparse, sys, time, re

def split_irc(message):
	message = re.sub("(?<=[0-9A-Fa-fI]):(?=[0-9A-Fa-fI])", "[..]", message)
	
	if ":" in message:
		first, second = message.split(":", 1)
		return first.rstrip().split(" ") + [second]
	else:
		return message.split(" ")

parser = argparse.ArgumentParser(description='Connects to an IRC network and executes a rakill.')

parser.add_argument('-H', dest='hostname', action='store', required=True,
                   help='server to connect to')
                   
parser.add_argument('-o', dest='port', action='store', required=True,
                   help='port* to connect to')

parser.add_argument('-u', dest='username', action='store', required=True,
                   help='oper username')
                   
parser.add_argument('-p', dest='password', action='store', required=True,
                   help='oper password')
                   
parser.add_argument('-r', dest='regex', action='store', required=True,
                   help='regex to match')
                   
parser.add_argument('-d', dest='duration', action='store', default="30d",
                   help='gline duration')
                   
parser.add_argument('-m', dest='message', action='store', default="You were banned during an automated bot kill. If this is in error, contact an operator.",
                   help='gline/kill message')


parser.add_argument('--list', dest='action_list', action='store_true',
                   help='list all matching users')

parser.add_argument('--gline', dest='action_gline', action='store_true',
                   help='gline all matching users')
                   
parser.add_argument('--kill', dest='action_kill', action='store_true',
                   help='kill all matching users')
                   
parser.add_argument('--unrealircd', dest='ircd_unreal', action='store_true',
                   help='assume UnrealIRCd')
                   
parser.add_argument('--inspircd', dest='ircd_insp', action='store_true',
                   help='assume InspIRCd')

args = parser.parse_args()
options = vars(args)

if options['ircd_unreal'] == False and options['ircd_insp'] == False:
	print "You did not specify an IRCd. Try again with --inspircd or --unrealircd switch."
	exit(1)

print "Connecting...",

sock = socket.socket()
sock.connect((options['hostname'], int(options['port'])))
readbuffer = ""

print "connected"

sock.send("NICK botkill\r\n")
sock.send("USER botkill %s 0 :rakill.py\r\n" % options['hostname'])

print "Registered."

while True:
	readbuffer = readbuffer + sock.recv(1024)
	lines = readbuffer.split("\n")
	readbuffer = lines.pop()
	
	for line in lines:
		if line.startswith(":"):
			line = line.split(" ", 1)[1]
			
		line = line.rstrip()
		parts = split_irc(line)
		
		if parts[0] == "PING":
			sock.send("PONG %s\r\n" % parts[1])
			print "Completed connection challenge."
		elif parts[0] == "001":
			sock.send("OPER %s %s\r\n" % (options['username'], options['password']))
		elif parts[0] == "381":
			print "Authenticated as oper."
			if options['ircd_insp'] == True:
				# InspIRCd
				sock.send("WHO ** h\r\n")
			elif options['ircd_unreal'] == True:
				# UnrealIRCd
				sock.send("WHO +hR **\r\n")
			print "Requested userlist."
		elif parts[0] == "352":
			try:
				ident = parts[3]
				host = parts[4].replace("[..]", ":")
				leaf = parts[5]
				nick = parts[6]
				realname = parts[8][3:]
				
				if re.match(options['regex'], nick):
					if options['action_gline']:
						sock.send("GLINE *@%s %s :[%s] %s\r\n" % (host, options['duration'], nick, options['message']))
						print "Glined *@%s" % host
					if options['action_kill']:
						sock.send("KILL %s :%s\r\n" % (nick, options['message']))
						print "Killed %s" % nick
					if options['action_list']:
						print "Matched user: %s!%s@%s" % (nick, ident, host)
			except IndexError:
				print "WARNING: Ignored user due to parsing error."
		elif parts[0] == "315":
			print "All users checked, exiting..."
			sock.send("QUIT :rakill.py bot killer\r\n")
			time.sleep(1)
			exit(0)
		elif parts[0] == "491":
			print "Invalid oper credentials given."
			exit(1)

	time.sleep(0.005)
