This repository has been archived by the owner on Sep 14, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathhintbot.py
executable file
·197 lines (175 loc) · 5.74 KB
/
hintbot.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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#!/usr/bin/python
# twisted imports
from twisted.words.protocols import irc
from twisted.internet import reactor, protocol
# SQLite
import sqlite3
# system imports
import sys, os.path
from time import gmtime, strftime
from GenericIRCBot import GenericIRCBot, GenericIRCBotFactory, log
class HintBot(GenericIRCBot):
def __init__(self):
self.commandData = {
"!help": {
"fn": self.handle_HELP,
"argc": 0,
"tillEnd": False,
"help": "this help text",
},
"!goto": {
"fn": self.handle_GOTO,
"argc": 1,
"tillEnd": False,
"help": "go to the given channel",
},
"!add": {
"fn": self.handle_ADD,
"argc": 1,
"tillEnd": True,
"help": "add a hint",
},
"!del": {
"fn": self.handle_DEL,
"argc": 1,
"tillEnd": True,
"help": "delete a hint by ID",
},
"!list": {
"fn": self.handle_LIST,
"argc": self.DontCheckARGC,
"tillEnd": True,
"help": "list all hints matching the given keywords",
},
"!hint": {
"fn": self.handle_HINT,
"argc": self.DontCheckARGC,
"tillEnd": True,
"help": "get a random hint matching the given ID or keywords",
},
}
self.commands = {
# only in direct user message, first word is the command
# dont allow !hint here. at least a little bit of public shaming.
"private": ["!help", "!add", "!del", "!list"],
# only in channels, first word must be the command
"public": ["!add", "!del", "!list", "!hint"],
# only in channels, first word is the name of this bot followed by a colon, second word is the command
"directed": ["!help", "!add", "!del", "!list", "!hint"],
}
def handle_GOTO(self, msgtype, user, recip, cmd, newchan): #{{{
if newchan.startswith("#"):
self.sendMessage(msgtype, user, recip, "joining %s" % newchan)
self.join(newchan)
#}}}
def handle_ADD(self, msgtype, user, recip, cmd, hint): #{{{
hintid = self.factory.db_addHint(hint)
self.sendMessage(msgtype, user, recip, "added hint id %d: %s" % (hintid, hint))
#}}}
def handle_DEL(self, msgtype, user, recip, cmd, hintid): #{{{
if not hintid.isdigit():
self.sendMessage(msgtype, user, recip, "The add command takes 1 numeric argument")
else:
hintid = int(hintid)
(success, hint) = self.factory.db_getHint(hintid)
if success:
self.factory.db_delHint(hintid)
self.sendMessage(msgtype, user, recip, "removed hint %d: %s" % (hintid, hint))
else:
self.sendMessage(msgtype, user, recip, "hint %d doesn't exist" % (hintid))
#}}}
def handle_HINT(self, msgtype, user, recip, cmd, keymsg=""): #{{{
key = keymsg.split()
if len(key) == 1 and key[0].isdigit():
hintid = int(key[0])
(success, hint) = self.factory.db_getHint(hintid)
else:
(success, hintid, hint) = self.factory.db_getRandomHint(key)
if success:
# allways reply in pm to prevent spoilers in the channel
self.sendMessage(msgtype, user, recip, "hint sent in pm")
self.sendMessage("private", user, recip, "Hint(%d): %s" % (hintid, hint))
else:
self.sendMessage(msgtype, user, recip, "no hints found")
#}}}
def handle_LIST(self, msgtype, user, recip, cmd, keymsg=""): #{{{
key = keymsg.split()
(success, hintids) = self.factory.db_getAllHints(key)
if success:
self.sendMessage(msgtype, user, recip, "Hint IDs: %s" % (",".join([str(x) for x in hintids])))
else:
self.sendMessage(msgtype, user, recip, "no hints found")
#}}}
def joined(self, channel):
pass
class HintBotFactory(GenericIRCBotFactory):
def __init__(self, proto, channel, nick, fullname, url): #{{{
GenericIRCBotFactory.__init__(self, proto, channel, nick, fullname, url)
# if the db file doesn't exist, create it
self.db_init("hints.db")
# }}}
def db_init(self, fn): #{{{
if os.path.exists(fn):
self.db = sqlite3.connect(fn)
else:
self.db = sqlite3.connect(fn)
cu = self.db.cursor()
cu.execute("create table hints (hint varchar)")
self.db.commit()
#}}}
def db_addHint(self, hint): #{{{
cu = self.db.cursor()
cu.execute("insert into hints values(?)", (hint,))
log("# Added hint %d" % cu.lastrowid)
self.db.commit()
return cu.lastrowid
#}}}
def db_delHint(self, hintid): #{{{
cu = self.db.cursor()
cu.execute("delete from hints where rowid=%d" % hintid)
log("# Deleted hint %d" % hintid)
self.db.commit()
#}}}
def db_getHint(self, hintid): #{{{
cu = self.db.cursor()
cu.execute("select hint from hints where rowid=%d" % hintid)
row = cu.fetchone()
if row:
hint = str(row[0])
log("# Getting hint %d: %s" % (hintid, hint))
return True, hint
else:
return False, 0
#}}}
def db_getAllHints(self, keys=[]): #{{{
cu = self.db.cursor()
key = "%" + "%".join(keys) + "%"
cu.execute("select rowid from hints where hint like ?", (key,))
rows = cu.fetchall()
if rows:
hintids = [int(x[0]) for x in rows]
log("# Getting all hint ids for [%s]: %s" % (key, ",".join([str(x) for x in hintids])))
return True, hintids
else:
return False, []
#}}}
def db_getRandomHint(self, keys=[]): #{{{
cu = self.db.cursor()
key = "%" + "%".join(keys) + "%"
cu.execute("select rowid, hint from hints where hint like ? order by random() limit 1", (key,))
row = cu.fetchone()
if row:
hintid = int(row[0])
hint = str(row[1])
log("# Getting random hint for %s: [%d] %s" % (key, hintid, hint))
return True, hintid, hint
else:
return False, 0, 0
#}}}
if __name__ == '__main__':
# create factory protocol and application
f = HintBotFactory(HintBot, ["#wargames"], "HintBot", "HintBot v1.1", "https://github.com/StevenVanAcker/OverTheWire-hintbot")
# connect factory to this host and port
reactor.connectTCP("irc.overthewire.org", 6667, f)
# run bot
reactor.run()