Aprovechando el PyIC escribí un bot que se une a un canal y responde a los típicos mensajes de "@loquesea" y "!loquesea", que están definidos en una base de datos SQLite3, la idea es algo así:
Se crea un archivo SQLite3 (por defecto el nombre es "dbase.db", si quieres puedes cambiarlo en la línea 12) con 2 tablas, "talks" y "commands".
La tabla "talks" tendría como mínimo 2 columnas, la primera es la palabra a la que responde, y la segunda, con lo que responde, por ejemplo, si la base de datos tiene esta fila:
busca | http://www.lmgtfy.com/?q=
El chat sería algo así
<humano>: @busca loquesea
< bot >: humano: http://www.lmgtfy.com/?q=loquesea
La tabla "commands" es mas o menos igual, dos columnas, la primera el comando, y la segunda lo que se ejecuta, por ejemplo...
info | uname
<humano>: !info -a
< bot >: humano: Linux blablabla 2.6.32-22-generic #36trisquel1 SMP Sat Jun 5 02:09:43 UTC 2010 i686 GNU/Linux
Solo decir que si despues del simbolo ('@'/'!') se escribe un nick seguido de ':', este será al que se hable...
<humano>: @humano2:busca loquesea
< bot >: humano2: http://www.lmgtfy.com/?q=loquesea
Y no se me ocurre que más comentar :P, aqui está el código [yabot.py], o coloreado...
#!/usr/bin/env python
# Ejemplo de cliente IRC con pyIC
from pyic import *
import sqlite3, os
botName = "vagoBot" # Nombre del bot
server = "irc.freenode.net" # Adivina xD
channel = "#bot_testing" # Canal al que se une el Bot
global db_file
db_file = "dbase.db" # Archivo sqlite3
def sayIt(irc, msg, ex):
to = msg.by
via = msg.to
mmsg = msg.msg
if ( via == irc.nick ):
via = msg.by
cc = 0
try:
cc = mmsg.index(":")
try:
sc = mmsg.index(" ")
if (sc > cc):
to = mmsg[ 0 : cc ]
except:
to = mmsg[ 0 : cc ]
cc += 1
mmsg = mmsg[ cc : ]
except:
pass
try:
i = mmsg.index(" ")
command = mmsg[ : i ]
args = mmsg[ i + 1 : ]
except:
command = mmsg
args = ""
conn = sqlite3.connect(db_file)
cur = conn.cursor()
if (not ex):
cur.execute("select * from talks")
else:
cur.execute("select * from commands")
for line in cur:
if (line[ 0 ] == command):
if ( not ex):
irc.notice( via, to + ": " + line[ 1 ] + args )
else:
p = os.popen( line[ 1 ] + args , "r" )
l = p.readline()
while ( len( l ) > 0 ):
while (l [ -1 ] == "\r" ) or (l [ -1 ] == "\n"):
l = l [ : -1 ]
irc.notice(via, to + ": " + l )
l = p.readline()
irc = irc_client(botName,server)
# Esperar por que acabe de "presentarse" el servidor
print "Esperando a que acabe de presentarse..."
while ( True ):
msg = irc.getmsg()
if ( msg.type == RPL_ENDOFMOTD ): # Fin del mensaje del dia
break
elif (msg.type == ERR_NOMOTD): # No hay mensaje del dia
break
print "Entrando a",channel
irc.join( channel ) # Se une al canal
# Saluda a todos los que hay en el canal
while ( True ):
msg = irc.getmsg()
if (msg.type.upper() == "PRIVMSG") or (msg.type.upper() == "NOTICE"):
msg.msg = msg.msg.strip()
if (msg.msg[ 0 ] == "!"):
msg.msg = msg.msg [ 1 : ]
sayIt(irc, msg, True)
elif (msg.msg[ 0 ] == "@" ):
msg.msg = msg.msg [ 1 : ]
sayIt(irc, msg, False)
Hasta otra!
Mostrando entradas con la etiqueta bot. Mostrar todas las entradas
Mostrando entradas con la etiqueta bot. Mostrar todas las entradas
jueves, 1 de julio de 2010
lunes, 28 de junio de 2010
IRC con Python (PyIC)
Si quieres programar algo que use IRC en Python puedes hacerlo tu mismo con sockets, puedes usar una librería y programarlo por eventos con pyirclib , PyIRC ...
A la hora de ver este tema, buscaba algo que se encargase de las cosas que no son interesantes del IRC (PING-PONG's, parseado de mensajes) y que no sea orientado a eventos, pero que siguiese permitiendo hacer cosas "poco comunes", como hacer que un archivo que se nos ofreció por esta red lo descargue directamente un servidor FTP (para eso hace falta algo mas, que la librería que trae python no lo permite), pero...
A falta de algo ya escrito, se programa, y eso es lo que traigo, otra librería de IRC más [ pyic.zip ]
El nombre... PyIRC ya estaba cogido xD, asi que supongo que valdrá PyIC (Python IRC Client)
Por si acaso lo dejo claro, la librería no descarga bien, así que no es recomendable usarlo para eso, ademas esta pensado para ser asíncrono, por ejemplo, no se pide la lista de canales y la propia librería la devuelve, sino que hace la peticion al servidor y es cosa del script capturar la lista (aunque la librería ya parsea los mensajes para hacer esta parte mas fácil), repito, no esta hecho para ser la forma mas sencilla, sino para permitir hacer cosas que otras no permiten.
Ahora explicaré las funciones que trae, pero para verlo mejor, aqui hay un pequeño bot que entra a un canal y saluda a los que llegan
#!/usr/bin/env python
# Ejemplo de cliente IRC con pyIC
from pyic import *
botName = "HelloBot"
server = "irc.freenode.net"
channel = "#bot_testing"
saludo = "Hola"
irc = irc_client(botName,server)
# Esperar por que acabe de "presentarse" el servidor
print "Esperando a que acabe de presentarse..."
while (True):
msg = irc.getmsg()
if ( msg.type == RPL_ENDOFMOTD ): # Fin del mensaje del dia
break
elif (msg.type == ERR_NOMOTD): # No hay mensaje del dia
break
print "Entrando a",channel
irc.join(channel) # Se une al canal
print "Saludando :)}"
irc.notice(channel,saludo+" "+channel) # Saluda al canal
# no usa irc.msg() para evitar que los bot's respondan
# Saluda a todos los que hay en el canal
while (True):
msg = irc.getmsg()
if (msg.type.upper()=="JOIN"): # Alguien mas entro al canal
if (msg.by != botName):
print "Llego",msg.by
irc.notice(channel,saludo+" "+msg.by)
No hace gran cosa, pero sirve como "Hola mundo" :)
Nota: Normalmente para hablar por el chat se utilizaria irc.sendmsg(), pero este protocolo definió especificamente un tipo de mensaje para que utilizaran los bots automáticos, a los cuales no se debería responder para evitar que varios robots entren en un bucle entre ellos... algo como esto (por decirlo de alguna forma)
Como se puede ver, todo se hace desde un objeto irc_client, que se inicializa con estos elementos:
A partir de esto, las funciones disponibles son:
La funcion getmsg() requiere una explicación aparte, pues es la que se utiliza para recuperar las comunicaciones del servidor al cliente, devuelve una variable de tipo irc_msg , con las siguientes propiedades:
Los nombres de los tipos de mensaje son los especificados por el RFC de IRC, ademas de "NOTICE" y "PRIVMSG", hay una lista en [ http://irchelp.org/irchelp/rfc/chapter6.html] (en inglés), aunque se añadio el "DCC_SEND_OFFER" para identificar las ofertas de envio de archivos
Si el mensaje es una oferta de DCC SEND (msg.type == DCC_SEND_OFFER ), además tiene las siguientes propiedades:
Queda por hacer (hoy no... mañaaaaana ):
IRC sobre SSL
Mucho de DCC: enviar, conexiones inversas,transmisiones cifradas... que funcione :P
[Referencias]
http://www.kvirc.de/docu/doc_dcc_connection.html
http://en.wikipedia.org/wiki/Direct_Client-to-Client
http://irchelp.org/irchelp/rfc/index.html
RFC 1459 (en español, version texto)
A la hora de ver este tema, buscaba algo que se encargase de las cosas que no son interesantes del IRC (PING-PONG's, parseado de mensajes) y que no sea orientado a eventos, pero que siguiese permitiendo hacer cosas "poco comunes", como hacer que un archivo que se nos ofreció por esta red lo descargue directamente un servidor FTP (para eso hace falta algo mas, que la librería que trae python no lo permite), pero...
A falta de algo ya escrito, se programa, y eso es lo que traigo, otra librería de IRC más [ pyic.zip ]
El nombre... PyIRC ya estaba cogido xD, asi que supongo que valdrá PyIC (Python IRC Client)
Por si acaso lo dejo claro, la librería no descarga bien, así que no es recomendable usarlo para eso, ademas esta pensado para ser asíncrono, por ejemplo, no se pide la lista de canales y la propia librería la devuelve, sino que hace la peticion al servidor y es cosa del script capturar la lista (aunque la librería ya parsea los mensajes para hacer esta parte mas fácil), repito, no esta hecho para ser la forma mas sencilla, sino para permitir hacer cosas que otras no permiten.
Ahora explicaré las funciones que trae, pero para verlo mejor, aqui hay un pequeño bot que entra a un canal y saluda a los que llegan
#!/usr/bin/env python
# Ejemplo de cliente IRC con pyIC
from pyic import *
botName = "HelloBot"
server = "irc.freenode.net"
channel = "#bot_testing"
saludo = "Hola"
irc = irc_client(botName,server)
# Esperar por que acabe de "presentarse" el servidor
print "Esperando a que acabe de presentarse..."
while (True):
msg = irc.getmsg()
if ( msg.type == RPL_ENDOFMOTD ): # Fin del mensaje del dia
break
elif (msg.type == ERR_NOMOTD): # No hay mensaje del dia
break
print "Entrando a",channel
irc.join(channel) # Se une al canal
print "Saludando :)}"
irc.notice(channel,saludo+" "+channel) # Saluda al canal
# no usa irc.msg() para evitar que los bot's respondan
# Saluda a todos los que hay en el canal
while (True):
msg = irc.getmsg()
if (msg.type.upper()=="JOIN"): # Alguien mas entro al canal
if (msg.by != botName):
print "Llego",msg.by
irc.notice(channel,saludo+" "+msg.by)
No hace gran cosa, pero sirve como "Hola mundo" :)
Nota: Normalmente para hablar por el chat se utilizaria irc.sendmsg(), pero este protocolo definió especificamente un tipo de mensaje para que utilizaran los bots automáticos, a los cuales no se debería responder para evitar que varios robots entren en un bucle entre ellos... algo como esto (por decirlo de alguna forma)
Como se puede ver, todo se hace desde un objeto irc_client, que se inicializa con estos elementos:
- nick: nick del usuario (elemental... xD)
- server: servidor IRC
- port: puerto del servidor (6667 por defecto)
- username: nombre de usuario ("user" por defecto)
- username2: segundo nombre del usuario ("user" por defecto)
- fullname: nombre completo del usuario ("user Name" by default)
- serverpasswd: contraseña para el servidor (si la tiene)
- passwd: contraseña para el nick (si la tiene)
A partir de esto, las funciones disponibles son:
- sendmsg(to,msg): envía un mensaje "msg" para "to"
- notice(to,msg): como sendmsg, pero este tipo de mensajes no se debe responder
- chng_nick(nick): cambia de nick
- join(channel,passwd=None): se une al canal "channel", usando una contraseña, si es necesaria (contraseña desactivada por defecto)
- quit(msg = "Client quit"): sale del servidor, con un mensaje "msg"
- quit_channel(channel): sale del canal "channel"
- kick(channel,nick,comment=None): echa a un usuario "nick" de un canal "channel", el comentario es opcional
- invite(nick,channel): invita a un usuario "nick" al canal "channel"
- get_channels(): pide la lista de canales
- get_names(channel): pide la lista de nicks en un canal "channel"
- get_topic(channel): pregunta al servidor el tema del canal "channel"
- set_topic(channel,topic): cambia el tema del canal "channel"
- whois(user): pide informacion acerca del usuario "user"
- whowas(user): pide informacion acerca del usuario "user" que ya no esta en el servidor
- set_mode(mode): cambia el modo del propio usuario
- set_chanmode(channel,mode,data = None): cambia al modo "mode" el canal "channel", si el modo requiere informacion adicional, se pasa a traves de "data"
La funcion getmsg() requiere una explicación aparte, pues es la que se utiliza para recuperar las comunicaciones del servidor al cliente, devuelve una variable de tipo irc_msg , con las siguientes propiedades:
- by: nick del emisor del mensaje
- sender: informacion del emisor
- to: a donde se envia (el usuario o un canal)
- type: tipo de mensaje: "PRIVMSG", "NOTICE", explico después un poco mas que es un poco largo
- msg: el mensaje
- multiline: si es un tipo de mensaje multilinea
- multiline_end: si es el fin de un mensaje multilinea
- ctcp: si contiene un mensaje CTPC
- ctcp_msg: mensaje ctcp
Los nombres de los tipos de mensaje son los especificados por el RFC de IRC, ademas de "NOTICE" y "PRIVMSG", hay una lista en [ http://irchelp.org/irchelp/rfc/chapter6.html] (en inglés), aunque se añadio el "DCC_SEND_OFFER" para identificar las ofertas de envio de archivos
Si el mensaje es una oferta de DCC SEND (msg.type == DCC_SEND_OFFER ), además tiene las siguientes propiedades:
- ip: IP de la conexión
- port: puerto de la conexión
- file: nombre del archivo
- turbo: si se usa el modo turbo
- size: tamaño del archivo (o -1 si no se especifica)
Queda por hacer (hoy no... mañaaaaana ):
IRC sobre SSL
Mucho de DCC: enviar, conexiones inversas,transmisiones cifradas... que funcione :P
[Referencias]
http://www.kvirc.de/docu/doc_dcc_connection.html
http://en.wikipedia.org/wiki/Direct_Client-to-Client
http://irchelp.org/irchelp/rfc/index.html
RFC 1459 (en español, version texto)
Suscribirse a:
Entradas (Atom)