-
Notifications
You must be signed in to change notification settings - Fork 0
/
bot.py
executable file
·180 lines (147 loc) · 5.37 KB
/
bot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#!/usr/bin/env python
__version__ = 0.1
__author__ = "Jonathan Heathcote"
import sys
import traceback
import pickle
from ircbot import SingleServerIRCBot
from irclib import nm_to_n, nm_to_h, irc_lower
from optparse import OptionParser
class IncompatibleModuleError(Exception):
"""
For raising when a module too new for this server is loaded
"""
pass
class BeardBot(SingleServerIRCBot):
def __init__(self, channel, server, port=6667, name="beardbot"):
SingleServerIRCBot.__init__(self, [(server, port)],
name,
"The Beardy-Based Botulator")
# The channel the bot is a member of
self.channel = channel
# The last place a message was recieved from (used by "reply")
self.last_message_sender = self.channel
# The loaded modules
self.modules = {}
# Try to load previously loaded modules
try:
old_modules = pickle.load(open(self.channel + "_modules.db", "r"))
for module in old_modules:
try:
self.load_module(module)
except Exception, e:
traceback.print_exc(file=sys.stdout)
except:
# Otherwise just start the admin
try:
self.load_module("admin")
except Exception, e:
print e
def get_nick(self):
"""Get the bot's nickname"""
return self.connection.get_nickname()
def set_nick(self, nick):
"""Set the bot's nickname"""
self.connection.nick(nick)
nick = property(fget=get_nick, fset=set_nick)
def say(self, message):
"""Send a message to the channel"""
self.pm(self.channel, message)
def reply(self, message):
"""Send a message to the last person to speak"""
self.pm(self.last_message_sender, message)
def pm(self, user, message):
"""Send a message to a user"""
message = message.replace("\r","\n")
for part in message.split("\n"):
self.connection.privmsg(user, part.encode("UTF8"))
def on_nicknameinuse(self, c, e):
c.nick(c.get_nickname() + "_")
def on_welcome(self, c, e):
c.join(self.channel)
#c.privmsg(self.channel, "Hi there, I'm beardy. If I'm annoying, tell me to die.")
def on_privmsg(self, c, e):
# Handle a message recieved from the channel
source_name = nm_to_n(e.source()).lower()
source_host = nm_to_h(e.source())
message = e.arguments()[0].decode("UTF8")
self.last_message_sender = source_name
for module in self.modules.values():
try:
module.handle_private_message(source_name, source_host, message)
except Exception, e:
traceback.print_exc(file=sys.stdout)
if message == "die":
# Force the bot to die
self.die("Someone killed me... It was you, " + nm_to_n(e.source()))
elif message == "panic:reloadadmin":
# Restart the admin module if something is going wrong
try:
self.load_module("admin")
except Exception, e:
print e
def on_pubmsg(self, c, e):
# Handle a message recieved from the channel
source_name = nm_to_n(e.source()).lower()
source_host = nm_to_h(e.source())
message = e.arguments()[0]
self.last_message_sender = self.channel
# If a message was addressed specifically to the bot, note this and strip
# this from the message
addressed_to_BeardBot = irc_lower(message).startswith("%s: " % self.nick.lower())
if addressed_to_BeardBot:
message = message.split(": ", 1)[-1]
# Alert each module that a message has arrived
for module in self.modules.values():
try:
if addressed_to_BeardBot:
module.handle_addressed_message(source_name, source_host, message.decode("UTF8"))
else:
module.handle_channel_message(source_name, source_host, message.decode("UTF8"))
except Exception, e:
traceback.print_exc(file=sys.stdout)
def load_module(self, module_name):
"""
Try to (re)load the named module.
"""
module = __import__(module_name)
reload(module)
if module_name in self.modules:
self.unload_module(module_name)
if module.requiredBeardBotVersion > __version__:
raise IncompatibleModuleError("%s requires BeardBot version %s"%(
module_name,
module.requiredBeardBotVersion))
# Try to load the module with a refrence to this bot
self.modules[module_name] = module.BeardBotModule(self)
def unload_module(self, module_name):
self.modules[module_name].die()
del self.modules[module_name]
def die(self, *args, **kwargs):
# Store a list of loaded modules before going down
pickle.dump(self.modules.keys(), open(self.channel + "_modules.db", "w"))
# Kill all the modules
for module in self.modules.values():
module.die()
# Disconnect and quit
SingleServerIRCBot.die(self, *args, **kwargs)
def main():
# Parse command line arguments.
parser = OptionParser()
parser.add_option("-r", "--room", dest="room", default="#uhc")
parser.add_option("-s", "--server", dest="server", default="irc.quakenet.org")
parser.add_option("-n", "--name", dest="name", default="beardbot")
(options, args) = parser.parse_args()
#prepend a '#' to the room if there isn't one.
room = options.room if options.room.startswith('#') else ("#" + options.room)
server = options.server
name = options.name
print "Starting '%s' in room '%s' on '%s'..." % (name, room, server)
# Run the bot.
bot = BeardBot(room, server, name=name)
try:
bot.start()
except KeyboardInterrupt:
bot.die()
if __name__ == "__main__":
main()