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
[email protected]
http://lists.python.it/mailman/listinfo/python