#!/usr/bin/env python
# -*- coding: utf-8 -*-
import xmpp
import commands
import time
import re
ADMIN_NAMES = [u'ВАШ@jabber.ru'] # ни с кем другим бот не будет общаться
BOT_NAME = ''
BOT_PASS = ''
########################################################################
class Bot():
CHAR_LIMIT = 1000 # кол-во символов за сообщение (от сервера)
TIMEOUT = 1 # пауза между ними
VERBOSE = 1 # вывод помногословней :)
#----------------------------------------------------------------------
def __init__(self, bot_jid, bot_pass, admin):
self.admin = admin
self.log = []
''' системные команды из питона не могут сменить pwd
родительского процесса - путь приходится сохранять и
делать cd перед командой '''
self.CWD = '~'
''' cтрока с прелестями функционального программирования
сначала отбирает из пространства имен те имена, что начинаются
на "cmd_", потом этот префикс отрезается. Тип не проверяется,
поэтому не надо создавать переменных класса с таким префиксом :)
Зато написав функцию с таким префиксом можно выполнять ее с ботом,
ибо ВНИМАНИЕ! - бот ваших алиасов не знает! '''
self.own_commands = map(lambda x: x.replace('cmd_', ''),
filter(lambda x: x.startswith('cmd_') == 1,
dir(self.__class__)))
''' соединяется с сервером, подробнее - в документации по xmpppy,
она идет с хорошими примерами. Или смотреть здесь:
http://xmpppy-guide.berlios.de/nightly/ '''
jid=xmpp.protocol.JID(bot_jid)
conn = xmpp.Client(jid.getDomain(), debug=[])
conn.connect()
conn.auth(jid.getNode(), bot_pass, resource=jid.getResource())
conn.sendInitPresence()
conn.RegisterHandler('message', self.messageCB)
conn.RegisterHandler('presence', self.presenceCB)
''' что-то вроде коннекта события
"message" - входящее сообщение
"presence" - запрос статуса (?)
с функцией-обработчиком, СB = callback ;) '''
if self.VERBOSE: print 'Own_commands', self.own_commands
''' запуск бесконечного цикла до прерывания с клавиатуры '''
while 1:
try:
conn.Process(1)
''' типа: "Я готов к обработке!"'''
except KeyboardInterrupt: break
#----------------------------------------------------------------------
def presenceCB(self, conn, msg):
user = msg.getFrom()
''' если это запрос авторизации от админа '''
if msg.getType() == "subscribe" and user.getStripped() in self.admin:
conn.send(xmpp.protocol.Presence(to = user, typ = 'subscribed')) # авторизуем
conn.send(xmpp.Presence(to = user, typ = 'subscribe')) # отправляем втречный запрос
#----------------------------------------------------------------------
def messageCB(self, conn, msg):
text=msg.getBody()
user=msg.getFrom().getStripped()
# getStripped() - отправитель без ресурса jabber (типа '/qutim')
if isinstance(text, unicode):
text = text.encode('utf-8') # иначе на русском символе мы запнемся
''' проверяем админ ли нам написал '''
if user not in self.admin:
conn.send(xmpp.protocol.Message(msg.getFrom(), 'Идите лесом.'))
''' функция отправки сообщения:
conn.send(xmpp.protocol.Message( JID, MESSAGE ) '''
if self.VERBOSE: print 'Нас пытались взломать!'
else:
if self.VERBOSE: print '%s: %s' % (user, text)
args = re.split(r'\s+', text)
''' разбивка на слова. Регулярка здесь потому, что
bash автоматически объединяет пробелы, а бот в своих
командах - нет '''
cmd = args.pop(0)
''' теперь args содержит все слова сообщения,
кроме первого, но возможно, что пустой список '''
if cmd in self.own_commands:
exec('self.cmd_%s(conn, msg, args)' % cmd)
''' вообще-то exec() - команда с дурной славой,
ибо там может оказаться и "import os; os.system('rm -rf /*')"
но здесь мы, во-первых, проверили пользователя,
а во-вторых - ограничились набором own_commands '''
else:
self.status, self.output = commands.getstatusoutput('(cd %s && %s)'
% (self.CWD, text))
''' commands.getstatusoutput возвращает
код выполнения последней системной команды
Вообще же это обертка на os.popen().read() '''
while self.output <> '':
conn.send(xmpp.protocol.Message(msg.getFrom(), self.output[:self.CHAR_LIMIT]))
''' при попытке от`cat`ать большой файл и отослать его,
меня отсылал куда подальше сервер джаббера.
То же было при отсутствии задержки.
В общем, эксперементируйте с константами - это не пределы '''
self.output = self.output[self.CHAR_LIMIT:]
time.sleep(self.TIMEOUT)
### LOG ###
self.log.append('%s:%s "%s" %s' % (time.localtime().tm_hour,
time.localtime().tm_min,
text,
self.status))
'''
#------------------------------------------------------------------
# Так можно писать свои дополнительные комманды
#------------------------------------------------------------------
def cmd_ИМЯ-КОММАНДЫ(self, conn, msg, args):
# args - список аргументов-СТРОК (уже без имени комманды)
# conn.send(xmpp.protocol.Message(msg.getFrom(), MESSAGE)
# self.status = 0
# будьте так любезны рапортовать об успехе/неудаче :)
'''
#----------------------------------------------------------------------
def cmd_cd(self, conn, msg, args):
""" cd args['path'] """
if args:
self.CWD = args[0]
else:
self.CWD = '~'
conn.send(xmpp.protocol.Message(msg.getFrom(), 'pwd = %s' % commands.getoutput('(cd %s && pwd)' % self.CWD)))
self.status = 0
#----------------------------------------------------------------------
def cmd_h(self, conn, msg, args):
""" args['n'] последних комманд """
if not args: args = ['3']
if args[0].isdigit():
n = int(args[0])
conn.send(xmpp.protocol.Message(msg.getFrom(), '\n'.join(self.log[-n:])))
self.status = 0
else:
conn.send(xmpp.protocol.Message(msg.getFrom(), 'h [кол-во команд]'))
self.status = 1
if __name__ == "__main__":
bot = Bot(BOT_NAME, BOT_PASS, ADMIN_NAMES)