| 1 | #!/usr/bin/env python
|
|---|
| 2 | # -*- coding: utf-8 -*-
|
|---|
| 3 | #
|
|---|
| 4 | # Copyright (C) 2007 Daniele Tricoli aka Eriol <eriol@mornie.org>
|
|---|
| 5 | # Copyright (C) 2010 Andrea Milazzo aka mancausoft <me@mancausoft.org>
|
|---|
| 6 | #
|
|---|
| 7 | # Daniele Tricoli, 2010 Reliceinsed to WTFPL
|
|---|
| 8 | #
|
|---|
| 9 | # This Program is free software. It comes without any warranty, to
|
|---|
| 10 | # the extent permitted by applicable law. You can redistribute it
|
|---|
| 11 | # and/or modify it under the terms of the Do What The Fuck You Want
|
|---|
| 12 | # To Public License, Version 2, as published by Sam Hocevar. See
|
|---|
| 13 | # http://sam.zoy.org/wtfpl/COPYING for more details.
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 | import os
|
|---|
| 17 | import re
|
|---|
| 18 |
|
|---|
| 19 | from twisted.words.protocols import irc
|
|---|
| 20 | from twisted.internet import reactor, protocol, ssl
|
|---|
| 21 |
|
|---|
| 22 | from dataslavebot import *
|
|---|
| 23 |
|
|---|
| 24 | import logging as log
|
|---|
| 25 | log.basicConfig(level=log.DEBUG,
|
|---|
| 26 | format='[%(asctime)s] %(levelname)s %(message)s',
|
|---|
| 27 | datefmt='%d/%m/%Y %H:%M:%S %Z',
|
|---|
| 28 | filename='slavebot.log',
|
|---|
| 29 | filemode='a')
|
|---|
| 30 | console = log.StreamHandler()
|
|---|
| 31 | console.setLevel(log.INFO)
|
|---|
| 32 | log.getLogger().addHandler(console)
|
|---|
| 33 |
|
|---|
| 34 |
|
|---|
| 35 | def save():
|
|---|
| 36 | f = open('dataslavebot.py', 'w')
|
|---|
| 37 | f.write('BOT_NICKNAME = "' + BOT_NICKNAME +'"\n')
|
|---|
| 38 | f.write('MASTER_USER = ' + str(MASTER_USER))
|
|---|
| 39 | f.write('\n\nRE_CONV = ' + str(RE_CONV))
|
|---|
| 40 | f.write('\nRE_CONV_ME = ' + str(RE_CONV_ME))
|
|---|
| 41 | f.write("\nOP_BOT = '"+ OP_BOT + "'\n")
|
|---|
| 42 | f.write('SERVER = '+ str(SERVER))
|
|---|
| 43 |
|
|---|
| 44 | class SlaveBot(irc.IRCClient):
|
|---|
| 45 |
|
|---|
| 46 | nickname = BOT_NICKNAME
|
|---|
| 47 |
|
|---|
| 48 | def __init__(self):
|
|---|
| 49 | self.op = False
|
|---|
| 50 | self.nicks = {}
|
|---|
| 51 |
|
|---|
| 52 | def opOnlyMaster (self, nick, channel):
|
|---|
| 53 | if ((nick in MASTER_USER) or (nick[:-1] in MASTER_USER) or (nick[:-2] in MASTER_USER)) and self.op:
|
|---|
| 54 | if nick == "tosky":
|
|---|
| 55 | self.msg(channel, "Ďekuji vám, pane " + nick + ", protože mi jste ctíl jako operátor.")
|
|---|
| 56 | elif nick == "geenna":
|
|---|
| 57 | self.msg(channel, "Grazie mio padrone " + nick + " mettiti a 90 che cominciamo!.")
|
|---|
| 58 | else:
|
|---|
| 59 | self.msg(channel, "Grazie mio padrone " + nick + " per avermi dato l'onore di poterti oppare.")
|
|---|
| 60 | self.sendLine('MODE ' + channel + ' +o ' + nick)
|
|---|
| 61 | self.nicks[nick] = 1
|
|---|
| 62 |
|
|---|
| 63 | def signedOn(self):
|
|---|
| 64 | log.info('Signed On:')
|
|---|
| 65 | for chan in self.factory.channel:
|
|---|
| 66 | self.join(chan)
|
|---|
| 67 |
|
|---|
| 68 | def joined(self, channel):
|
|---|
| 69 | log.info('Joined: %s', channel)
|
|---|
| 70 | self.nicks = {}
|
|---|
| 71 | self.msg(channel, "Grazie di avermi creato, datemi l'onore del'op e saro' il vostro schiavo per il resto della mia vita")
|
|---|
| 72 |
|
|---|
| 73 | def action (self, username, channel, emote):
|
|---|
| 74 | if (emote.find("si inchina") != -1) or (emote.find("s'inchina") != -1):
|
|---|
| 75 | self.msg(channel, username.split('!')[0] + ": Stai attento in questo canale e' pericoloso fare cose del genere!")
|
|---|
| 76 |
|
|---|
| 77 | def userLeft (self, user, channel):
|
|---|
| 78 | del self.nicks[user]
|
|---|
| 79 |
|
|---|
| 80 | def userRenamed(self, oldname, newname):
|
|---|
| 81 | self.nicks[newname] = self.nicks[oldname]
|
|---|
| 82 | del self.nicks[oldname]
|
|---|
| 83 |
|
|---|
| 84 | def userJoined (self, user, channel):
|
|---|
| 85 | self.me(channel, "si prostra davanti a " + user)
|
|---|
| 86 | self.nicks[user] = 0
|
|---|
| 87 | self.opOnlyMaster(user, channel)
|
|---|
| 88 |
|
|---|
| 89 | def irc_RPL_NAMREPLY(self, prefix, params):
|
|---|
| 90 | log.info('irc_RPL_NAMREPLY')
|
|---|
| 91 | nicks = params[3].split()
|
|---|
| 92 | for nick in nicks:
|
|---|
| 93 | if nick[0] == '@':
|
|---|
| 94 | self.nicks[nick[1:]] = 1
|
|---|
| 95 | else:
|
|---|
| 96 | self.nicks[nick] = 0
|
|---|
| 97 | if OP_BOT in self.nicks.keys():
|
|---|
| 98 | self.msg(params[2], "ciao " + OP_BOT)
|
|---|
| 99 |
|
|---|
| 100 | def irc_ERR_NICKNAMEINUSE (self, prefix, params):
|
|---|
| 101 | self.nickname = self.nickname + "_"
|
|---|
| 102 | self.setNick(self.nickname)
|
|---|
| 103 |
|
|---|
| 104 | def privmsg(self, user, channel, message):
|
|---|
| 105 | user = user.split('!')[0]
|
|---|
| 106 | if channel != self.nickname:
|
|---|
| 107 | for regexp in RE_CONV:
|
|---|
| 108 | rexp = re.sub('(?i)\$bot', self.nickname, regexp)
|
|---|
| 109 | try:
|
|---|
| 110 | if re.search(rexp, message, re.IGNORECASE):
|
|---|
| 111 | msg = re.sub('(?i)\$nick', user, RE_CONV[regexp])
|
|---|
| 112 | self.msg(channel, re.sub('(?i)\$bot', self.nickname, msg))
|
|---|
| 113 | except:
|
|---|
| 114 | print "ERRORE PORC!"
|
|---|
| 115 | for regexp in RE_CONV_ME:
|
|---|
| 116 | rexp = re.sub('(?i)\$bot', self.nickname, regexp)
|
|---|
| 117 | if re.search(rexp, message, re.IGNORECASE):
|
|---|
| 118 | msg =re.sub('(?i)\$nick', user, RE_CONV_ME[regexp])
|
|---|
| 119 | self.me(channel, re.sub('(?i)\$bot', self.nickname, msg))
|
|---|
| 120 | if re.search(self.nickname, message, re.IGNORECASE):
|
|---|
| 121 | if re.search('aiutami|help', message, re.IGNORECASE):
|
|---|
| 122 | self.msg(channel, self.polygen('if')[:440].rsplit('.',1)[0] + '.')
|
|---|
| 123 | elif re.search('spot', message, re.IGNORECASE):
|
|---|
| 124 | self.msg(channel, self.polygen('poster').replace('\n',''))
|
|---|
| 125 | elif re.search('consigli', message, re.IGNORECASE):
|
|---|
| 126 | msg = self.polygen('kamasutra')
|
|---|
| 127 | m = re.search('(?i)\<strong\> (.*) \</strong\>', msg)
|
|---|
| 128 | message = m.groups()[0]
|
|---|
| 129 | m = re.search('\</strong\>.*\n.*\n+(.*)', msg)
|
|---|
| 130 | message += ': ' + m.groups()[0]
|
|---|
| 131 | self.msg(channel, message)
|
|---|
| 132 |
|
|---|
| 133 | else:
|
|---|
| 134 | if re.match('(?i) *LIST( |$)', message):
|
|---|
| 135 | self.msg(user, "MESSAGE: ")
|
|---|
| 136 | for i in RE_CONV:
|
|---|
| 137 | self.msg(user, i + " -> " + RE_CONV[i])
|
|---|
| 138 | self.msg(user, "/ME: ")
|
|---|
| 139 | for i in RE_CONV_ME:
|
|---|
| 140 | self.msg(user, i + " -> " + RE_CONV_ME[i])
|
|---|
| 141 |
|
|---|
| 142 | m = re.match('(?i) *ADD +"(.*)".*,.*"(.*)"', message)
|
|---|
| 143 | if m:
|
|---|
| 144 | RE_CONV[m.groups()[0]] = m.groups()[1]
|
|---|
| 145 | for i in RE_CONV:
|
|---|
| 146 | self.msg(user, i + " -> " + RE_CONV[i])
|
|---|
| 147 | log.info(user + ": "+ message)
|
|---|
| 148 | save()
|
|---|
| 149 |
|
|---|
| 150 | m = re.match('(?i) *DEL +"(.*)".*', message)
|
|---|
| 151 | if m:
|
|---|
| 152 | del RE_CONV[m.groups()[0]]
|
|---|
| 153 | for i in RE_CONV:
|
|---|
| 154 | self.msg(user, i + " -> " + RE_CONV[i])
|
|---|
| 155 | log.info(user + ": "+ message)
|
|---|
| 156 | save()
|
|---|
| 157 |
|
|---|
| 158 | m = re.match('(?i) *ADDME +"(.*)".*,.*"(.*)"', message)
|
|---|
| 159 | if m:
|
|---|
| 160 | RE_CONV_ME[m.groups()[0]] = m.groups()[1]
|
|---|
| 161 | for i in RE_CONV_ME:
|
|---|
| 162 | self.msg(user, i + " -> " + RE_CONV_ME[i])
|
|---|
| 163 | log.info(user + ": "+ message)
|
|---|
| 164 | save()
|
|---|
| 165 |
|
|---|
| 166 | m = re.match('(?i) *DELME +"(.*)".*', message)
|
|---|
| 167 | if m:
|
|---|
| 168 | del RE_CONV_ME[m.groups()[0]]
|
|---|
| 169 | for i in RE_CONV_ME:
|
|---|
| 170 | self.msg(user, i + " -> " + RE_CONV_ME[i])
|
|---|
| 171 | log.info(user + ": "+ message)
|
|---|
| 172 | save()
|
|---|
| 173 |
|
|---|
| 174 | m = re.match('(?i) *NICK +"(.*)".*', message)
|
|---|
| 175 | if m:
|
|---|
| 176 | BOT_NICKNAME = m.groups()[0]
|
|---|
| 177 | self.nickname = BOT_NICKNAME
|
|---|
| 178 | self.setNick(self.nickname)
|
|---|
| 179 | save()
|
|---|
| 180 |
|
|---|
| 181 | m = re.match('(?i) *TALK +(.*)', message)
|
|---|
| 182 | if m:
|
|---|
| 183 | msg = m.groups()[0].split(' ',1)
|
|---|
| 184 | self.msg(msg[0], msg[1])
|
|---|
| 185 |
|
|---|
| 186 | m = re.match('(?i) *ADDOP +(.*)', message)
|
|---|
| 187 | if m:
|
|---|
| 188 | for nick in m.groups()[0].split(' '):
|
|---|
| 189 | MASTER_USER.append(nick)
|
|---|
| 190 | self.msg(user, str(MASTER_USER))
|
|---|
| 191 | save()
|
|---|
| 192 |
|
|---|
| 193 | if re.match('(?i) *HELP *.*', message):
|
|---|
| 194 | self.msg(user.split('!')[0], 'TALK #channel message | LIST | ADD "reg-exp", "message" | DEL "regexp" | ADDME "reg-exp", "message" | DELME "regexp" | NICK "NEW NICK"')
|
|---|
| 195 | self.msg(user.split('!')[0], 'In message you can use $nick. $nick will replace with the name to sender.')
|
|---|
| 196 | self.msg(user.split('!')[0], 'In message and regexp you can use $bot. $bot will replace with the name to bot.')
|
|---|
| 197 |
|
|---|
| 198 | def modeChanged (self, user, channel, set, modes, args):
|
|---|
| 199 | toOp = False
|
|---|
| 200 | for i in range(len(args)):
|
|---|
| 201 | if modes[i] == 'o':
|
|---|
| 202 | user = user.split('!')[0]
|
|---|
| 203 | self.op = set
|
|---|
| 204 | if set:
|
|---|
| 205 | if args[i] == self.nickname:
|
|---|
| 206 | self.msg(channel, "Grazie " + user + " saro' il vostro schiavo per il resto della mia vita.")
|
|---|
| 207 | toOp = True
|
|---|
| 208 | self.nicks[args[i]] = 1
|
|---|
| 209 | else:
|
|---|
| 210 | if args[i] == self.nickname:
|
|---|
| 211 | self.msg(channel, "Grazie " + user + " non sono degno di essere il vostro schiavo. La mia vita e' nelle vostre mani!")
|
|---|
| 212 | self.nicks[args[i]] = 0
|
|---|
| 213 | if toOp:
|
|---|
| 214 | for nick in self.nicks:
|
|---|
| 215 | if self.nicks[nick] == 0 and nick != BOT_NICKNAME:
|
|---|
| 216 | self.opOnlyMaster(nick, channel)
|
|---|
| 217 |
|
|---|
| 218 | def polygen (self, name):
|
|---|
| 219 | filename = '/usr/share/polygen/ita/' + name + '.grm'
|
|---|
| 220 | prog = os.popen("polygen " + filename)
|
|---|
| 221 | return prog.read()
|
|---|
| 222 |
|
|---|
| 223 | def ctcpUnknownQuery (self, user, channel, tag, data):
|
|---|
| 224 | pass
|
|---|
| 225 |
|
|---|
| 226 | class SlaveBotFactory(protocol.ClientFactory):
|
|---|
| 227 |
|
|---|
| 228 | protocol = SlaveBot
|
|---|
| 229 |
|
|---|
| 230 | def __init__(self, channel):
|
|---|
| 231 | self.channel = channel
|
|---|
| 232 |
|
|---|
| 233 | def clientConnectionLost(self, connector, reason):
|
|---|
| 234 | log.critical('Connection lost: %s', reason)
|
|---|
| 235 | connector.connect()
|
|---|
| 236 |
|
|---|
| 237 | def clientConnectionFailed(self, connector, reason):
|
|---|
| 238 | log.critical('Connection failed: %s', reason)
|
|---|
| 239 | connector.connect()
|
|---|
| 240 |
|
|---|
| 241 | if __name__ == '__main__':
|
|---|
| 242 |
|
|---|
| 243 | for server in SERVER:
|
|---|
| 244 | f = SlaveBotFactory(server['channel'])
|
|---|
| 245 | if server['ssl'] == 1:
|
|---|
| 246 | contextFactory = ssl.ClientContextFactory()
|
|---|
| 247 | reactor.connectSSL(server['name'], server['port'], f, contextFactory)
|
|---|
| 248 | else:
|
|---|
| 249 | reactor.connectTCP(server['name'], server['port'], f)
|
|---|
| 250 | reactor.run()
|
|---|