Salve a tutti.
Sto scrivendo un Bot IRC in Python, e sono arrivato a un bot
completamente funzionante, così volevo migliorare la struttura, in modo
che fosse più facilmente estendibile.
Ora, come potete vedere nello script allegato, nella classe Rule ho
tante funzioni, una per ogni tipo di regola (e quindi di azione da
compiere). Ad esempio, c'è una funzione per una risposta random, una per
eseguire comandi shell, una per il bruteforce di hash md5 e così via.
Ora, se voglio aggiungere una nuova funzionalità, devo modificare il
sorgente aggiungendo la funzione desiderata, ed aggiungerla nel
dizionario "self.internal_rules". Per maggiore comodità ed estendibilità
pensavo di mettere tutte queste funzioni dentro una cartella come
moduli, ad esempio random.py, shell.py, bruteforce.py e cosi via, e il
bot all'avvio controlla tutti i moduli presenti e crea in base al nome
del file il dizionario internal_rules. il mio problema è che in base al
tipo di regola devo importare il modulo corrispondente, se ad esempio
deve compiere un processo shell deve usare il modulo shell.py, ma dato
che non posso fare import <variabile> poichè dopo import viene sempre
considerato come stringa (o no? =|) come posso fare? Cercando in giro ho
trovato il modulo imp e funzioni come imp.load_source ma non ho capito
bene.
Quindi mi sarebbe d'aiuto un buon metodo per importare moduli a seconda
di una variabile, o altri modo per definire ed utilizzare funzioni in
files esterni al "cuore" del programma.
Grazie per le eventuali risposte :)
#! /usr/bin/python
# -*- coding: UTF-8 -*-

""" PyBOT: Bot IRC in python. Creato da Learts

    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.

	Dedicato al grande, l'inimitabile, l'incesurabile, l'imbannabile, l'invincibile, l'inbattibile, l'indistruttibile, l'inimitabile Chuck Norris!
"""   
__module_name__ = "PyBOT"
__module_version__ = __revision__ = "1.0Alpha2"
__module_description__ = "Bot IRC scritto in Python"

"""
	TODO: 
	 - Accetta comandi solo se all'inizio del messaggio o, se in mezzo al messaggio, il messaggio deve contenere il nick del bot.
	 	Utile nel caso di più bot presenti contemporaneamente"
	 - Elimina punto di domanda da si/no (ancora qualche dubbio se sia da fare o meno)
	 - Strutturare lo script in modo che siano facilmente aggiungibili altre regole
	 - Funzione per salvare/caricare delle regole
	 - Interazione con l'utente per la creazione di regole pre-bot
	 
	 Si pensava di strutturare così il tutto: un modulo con le funzioni necessarie al bot (comune per tutte le istanze dei bot), un modulo con
	 tutte le funzioni delle regole (comune a tutti i bot) , un file con le regole (diverso per ogni istanza del bot), uno script per creare/salvare/
	 caricare e modificare files di regole (unico)

"""

import socket
import random

class Rule:
	autorizzati = []
	negati = []
	
	def __init__(self, name, keys, mode, help, response=None, variables=None):
		self.name = name
		self.keys = keys
		self.func = mode
		self.help = help
		print response and setattr(self, 'response', response) or '0' #Crea l'attributo solo se esiste, per non crearlo con valore None
		print variables and setattr(self, 'variables', variables) or '0'
		self.internal_rules = {'normal' : self.normal, 'random' : self.random, 'oneof' : self.one_of, 'auth' : self.auth, 'randomauth' : self.random_auth, 'checkauth' : self.check_auth, 'kick' : self.kick, 'disconnect' : self.disconnect, 'rejoin' : self.rejoin, 'say' : self.say, 'help' : self.send_help, 'join' : self.join, 'sys' : self.sys, 'leave' : self.leave, 'md5dec': self.find_md5}
	
	def __str__(self):
		return self.name
	
	def is_verified(self, server_response):
		for groupkey in self.keys:
			for key in groupkey:
				if key in server_response:
					self.written_key = key
					break
			else:
				return 0
		return 1
	
	def compile_rule(self, server_response):
		return self.internal_rules[self.func](server_response)
	
	def get_params(self, server_response):
		server_response = server_response.split(':', 2)
		try:
			user = server_response[1].split('!', 1)[0]
		except:
			user = 'gino'
		try:
			mode = server_response[1].split()[1]
		except:
			mode = ''
		try:
			chan = server_response[1].split()[2]
		except:
			chan = ''
		try:
			request = server_response[2].split(self.written_key, 1)[1].lstrip()
		except:
			request = ''
		return user, mode, chan, request
	
	def compile_message(self, message, user, request):
		return message.replace('$user', user).replace('$request', request)
				
	def kick(self):
		try:
			self.Bot.Socket.send("KICK %s %s :%s" % (self.chan, self.user, self.Params))
		except:
			pass
				
	def send(self, message, chan):
		self.Bot.Socket.send('PRIVMSG %s :%s\n' % (chan, message))
		return 'Message sent'
		
	def normal(self, server_response):
		user, mode, chan, request = self.get_params(server_response)
		message = self.compile_message(self.response, user, request)
		return self.send(message, chan)
		
	def one_of(self, server_response):
		user, mode, chan, request = self.get_params(server_response)
		message = self.compile_message(self.response[int(request) - 1], user, request)
		return self.send(message, chan)
		
	def auth(self):
		pass
		
	def random_auth(self, server_response):
		user, mode, chan, request = self.get_params(server_response)
		a, me = self.random(server_response)
		if self.variables in me:
			self.negati.append(user)
			print '%s è stato negato' % user
		else:
			self.autorizzati.append(user)
			print '%s è stato autorizzato' % user
		
	def check_auth(self, server_response):
		user, mode, chan, request = self.get_params(server_response)
		if user in self.autorizzati:
			print 'Autorizzato'
			return self.send(self.compile_message(self.response[0], user, request), chan)
		elif user in self.negati:
			print 'Negato'
			return self.send(self.compile_message(self.response[1], user, request), chan)
		else:
			print 'Niente'
			return self.send(self.compile_message(self.response[2], user, request), chan)
		
	def random(self, server_response):
		user, mode, chan, request = self.get_params(server_response)
		message = self.compile_message(self.response[random.randrange(len(self.response))], user, request)
		return self.send(message, chan), message
	
	def disconnect(self, server_response):
		user, mode, chan, request = self.get_params(server_response)
		print "Ricevuto comando di disconnessione da " + user
		if user == self.Bot.owner:
			self.Bot.disconnect(request)

	def rejoin(self, server_response):
		user, mode, chan, request = self.get_params(server_response)
		if self.Bot.nick in server_response:
			print "Sono stato kikkato!"
			self.Bot.join(chan)
			self.send(self.response, chan)
	
	def say(self, server_response):
		user, mode, chan, request = self.get_params(server_response)
		canale, text = request.split(' ', 1)
		if user == self.Bot.owner:
			return self.send(text, canale)
	
	def join(self, server_response):
		user, mode, chan, request = self.get_params(server_response)
		if user == self.Bot.owner:
			self.Bot.join(request)
	
	def leave(self, server_response):
		user, mode, chan, request = self.get_params(server_response)
		request = request and request or chan
		print request
		if user == self.Bot.owner:
			self.Bot.Socket.send("PART %s \n" % request)
		else:
			self.send("Accetto ordini solo da %s" % self.Bot.owner, chan)
			
	def sys(self, server_response):
		import os
		user, mode, chan, request = self.get_params(server_response)
		if user == self.Bot.owner:
			f = os.popen(request)
			for line in f:
				self.send(line, chan)
			return self.send("End of %s" % request, chan)
		else:
			return self.send("Non sei autorizzato", chan)
	
	def find_md5(self, server_response):
		import md5dec
		user, mode, chan, request = self.get_params(server_response)
		m = md5dec.md5_bruteforcer(33, 127, 3)
		try:
			if user == self.Bot.owner:
				res = m.complete_check(request)
				if res == None:
					return self.send("Stringa originaria non trovata, probabilmente è più lunga di %i caratteri" % m.max_chars, chan)
				return self.send("%s è l'hash di: %s" % (request, res), chan)
			else:
				return self.send("Non sei autorizzato a fondermi la CPU", chan)
		except:
			return self.send("Hash md5 non valido", chan)

	def send_help(self, server_response):
		user, mode, chan, request = self.get_params(server_response)
		if request:
			for rule in self.Bot.rules:
				if rule.name == request:
					self.send(rule.help, chan)
					break
			else:
				message = self.compile_message("Nessun comando/regola con nome '$request'", user, request)
				self.send(message, chan)
		else:
			text = ', '.join(map(str, self.Bot.rules))
			self.send(text, chan)
			
class Bot:
	def __init__(self, nick, owner, password = 0,):
		self.nick = nick
		self.owner = owner
		self.password = password
		self.rules = []
		self.connected = 0
		self.channels = []
	
	def connect(self, server, porta=6667):
		"""utilizzo: nomebot.connect(server, porta)\n Connette il bot al server specificato, passando dalla porta specificata.""" 
		self.Socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		self.Socket.connect((server, porta))
		self.Socket.send('USER %s "desktop" "freenode" :%s\n' % (self.nick, self.nick))
		self.Socket.send("NICK %s\n" % self.nick)
		print 'Connesso'
		print self.password and self.Socket.send("NS IDENTIFY %s\n" % self.password) or 'Nessuna password specificata, identificazione non effettuata\n'
		self.connected = 1
		
	def disconnect(self, message='Bye'):
		"""Disconnette il bot"""
		if not self.connected:
			print "Non sei connesso"
		else:
			self.Socket.send("QUIT :%s \n" % message) 
			for channel in self.channels: self.channels.remove(channel)
			self.connected = 0
		
	def join(self, canale):
		"""joina il canale specificato"""
		print self.connected and (self.Socket.send("JOIN %s\n" % canale), self.channels.append(canale))  or "Devi prima connetterti!"
	
	def add_rule(self, rule):
		self.rules.append(rule)
		rule.Bot = self
	
	def apply_rules(self):
		while self.connected:
			server_response = self.Socket.recv(4096).rstrip('\r\n')
			print server_response
			print
			try:
				for rule in self.rules:
					if rule.is_verified(server_response):
						print 'Regola verificata'
						print rule.compile_rule(server_response)
						break
			except:
				pass

if __name__ == '__main__':
	permesso = Rule('permesso', [['!permesso']], 'randomauth', "Da o nega il permesso per la richiesta. Usage: !permesso richiesta", ['$user, hai il mio permesso per $request', '$user, NON hai il mio permesso'], 'NON')
	grazie = Rule('grazie', [['grazie', 'Grazie'], ['Chuck', 'chuck']], 'normal', "Ringraziarmi è giusto", "Ringraziare Chuck Norris è cosa buona e giusta")
	say = Rule('say', [['!say']], 'say', "Dico quello richiesto nel canale specificato. Al momento bisogna avere dei permessi speciali per usare !say. Usage: !say canale richiesta")
	sino = Rule('si/no', [['!sino']], 'random', "Random: Si o No", ['SI, sicuramente $request', 'Può darsi che $request', 'No, non penso che $request'])
	help = Rule('help', [['!help']], 'help', "Funzione d'aiuto. Se chiamata semplicemente '!help' mostra tutti i possibili comandi, se chiamata come !help nomecomando mostra l'help specifico del comando")
	join = Rule('join', [['!join']], 'join', "Joino il canale specificato.B isogna avere dei permessi speciali per usare !join. Usage: !join canale")
	sys = Rule('sys', [['!sys']], 'sys', "Eseguo il comando in una shell e mando l'output. Al momento bisogna avere dei permessi speciali per usare !sys. Usage: !sys comando")
	leave = Rule('leave', [['!leave']], 'leave', "Lascio il canale specificato. Al momento bisogna avere dei permessi speciali per usare !leave. Usage: leave channel. Se channel non è specificato lascio il canale corrente")
	bruteforce = Rule('bruteforce', [['!bruteforce']], 'md5dec', "Trova la stringa originaria di un hash md5 con la tecnica del bruteforcing. Stringhe originarie di massimo 3 caratteri. Usage: !bruteforce hash_md5")
	disconnect = Rule('disconnect', [['!disconnect']], 'disconnect', "Mi disconnetto. Al momento bisogna avere dei permessi speciali per usare !disconnect. Usage: !disconnect messaggio_uscita (il messaggio d'uscita è momentaneamente non funzionante)")
	kick = Rule('auto-rejoin', [['KICK']], 'rejoin', "Funzione automatica per l'auto-rejoin")
	C = Bot('|Chuck_Norris|', '_Learts_')
	C.add_rule(permesso)
	C.add_rule(grazie)
	C.add_rule(say)
	C.add_rule(sino)
	C.add_rule(help)
	C.add_rule(sys)
	C.add_rule(leave)
	C.add_rule(bruteforce)
	C.add_rule(disconnect)
	C.add_rule(kick)
	C.add_rule(join)
	C.connect('irc.freenode.org')
	C.join('#PTA')
	C.join('#tremulous.ita')
	C.apply_rules()
_______________________________________________
Python mailing list
Python@lists.python.it
http://lists.python.it/mailman/listinfo/python

Rispondere a