1
2
3
4
5
6 """ a bot object handles the dispatching of commands and check for callbacks
7 that need to be fired """
8
9 __copyright__ = 'this file is in the public domain'
10
11 from gozerbot.generic import rlog, handle_exception, getlistensocket, \
12 stripident, checkchan, waitforqueue, uniqlist, strippedtxt, makeargrest
13 from gozerbot.commands import cmnds
14 from gozerbot.callbacks import callbacks
15 from gozerbot.plugins import plugins
16 from gozerbot.users import users
17 from gozerbot.datadir import datadir
18 from gozerbot.partyline import partyline
19 from gozerbot.monitor import outmonitor
20 from gozerbot.irc import Irc
21 from gozerbot.ircevent import Ircevent
22 from gozerbot.channels import Channels
23 from gozerbot.config import config
24 from gozerbot.wait import Privwait
25 from gozerbot.thr import start_new_thread
26 from gozerbot.dol import Dol
27 from gozerbot.fleet import fleet
28 from gozerbot.persiststate import PersistState
29 from gozerbot.runner import runners_start
30
31 import re, socket, struct, Queue, time, os, types
32
33 dccchatre = re.compile('\001DCC CHAT CHAT (\S+) (\d+)\001', re.I)
34
36
37 """ class that dispatches commands and checks for callbacks to fire """
38
39 - def __init__(self, name = 'main', owner=[]):
52
54 return "name: %s nick: %s server: %s ipv6: %s ssl: %s port:%s" % (self.name, \
55 self.nick, self.server, self.ipv6, self.ssl, self.port)
56
63
64 - def _dccresume(self, sock, nick, userhost, channel=None):
65 """ loop for dcc commands """
66 if not nick or not userhost:
67 return
68 start_new_thread(self._dccloop, (sock, nick, userhost, channel))
69
71 """ accept dcc chat requests """
72 try:
73
74 listenip = socket.gethostbyname(socket.gethostname())
75 (port, listensock) = getlistensocket(listenip)
76
77 ipip2 = socket.inet_aton(listenip)
78 ipip = struct.unpack('>L', ipip2)[0]
79
80 chatmsg = 'DCC CHAT CHAT %s %s' % (ipip, port)
81 self.ctcp(nick, chatmsg)
82
83 sock = listensock.accept()[0]
84 except Exception, ex:
85 rlog(10 , self.name, 'dcc error: %s' % str(ex))
86 return
87
88 self._dodcc(sock, nick, userhost, channel)
89
90 - def _dodcc(self, sock, nick, userhost, channel=None):
91 """ loop for dcc commands """
92 if not nick or not userhost:
93 return
94 try:
95
96 cmndslist = cmnds.list('USER')
97 cmndslist.sort()
98 sock.send('Welcome to the GOZERBOT partyline ' + nick + " ;]\n")
99 partylist = partyline.list_nicks()
100 if partylist:
101 sock.send("people on the partyline: %s\n" % \
102 ' .. '.join(partylist))
103 sock.send("control character is ! .. bot broadcast is @\n")
104 except Exception, ex:
105 rlog(10 , self.name, 'dcc error: %s' % str(ex))
106 return
107 start_new_thread(self._dccloop, (sock, nick, userhost, channel))
108
109 - def _dccloop(self, sock, nick, userhost, channel=None):
110 sockfile = sock.makefile('r')
111 res = ""
112
113 partyline.add_party(self, sock, nick, userhost, channel)
114 while 1:
115 time.sleep(0.001)
116 try:
117
118 res = sockfile.readline()
119
120 if self.stopped or not res:
121 rlog(1, self.name, 'closing dcc with ' + nick)
122 partyline.del_party(nick)
123 return
124 except socket.timeout:
125
126 continue
127 except socket.error, ex:
128
129 try:
130 (errno, errstr) = ex
131 except:
132 errno = 0
133 errstr = str(ex)
134 if errno == 35 or errno == 11:
135 continue
136 else:
137 raise
138 except Exception, ex:
139
140 handle_exception()
141 rlog(10, self.name, 'closing dcc with ' + nick)
142 partyline.del_party(nick)
143 return
144 try:
145
146 res = strippedtxt(res.strip())
147 chan = checkchan(self, res)
148 if chan != None:
149 (channel, res) = chan
150 else:
151 channel = ''
152
153 ievent = Ircevent()
154 ievent.nick = nick
155 ievent.userhost = userhost
156 ievent.channel = channel
157 ievent.origtxt = res
158 ievent.txt = res
159 ievent.cmnd = 'DCC'
160 ievent.bot = self
161 ievent.sock = sock
162 ievent.speed = 1
163
164 if ievent.txt[0] == "!":
165 ievent.txt = ievent.txt[1:]
166 plugins.trydispatch(self, ievent)
167 continue
168 elif ievent.txt[0] == "@":
169
170
171 partyline.say_broadcast_notself(ievent.nick, \
172 "[%s] %s" % (ievent.nick, ievent.txt))
173
174
175 q = Queue.Queue()
176 ievent.queues = [q]
177 ievent.txt = ievent.txt[1:]
178 plugins.trydispatch(self, ievent)
179
180 result = waitforqueue(q, 5)
181 if result:
182
183 for i in result:
184 partyline.say_broadcast("[bot] %s" % i)
185 continue
186 else:
187
188 partyline.say_broadcast_notself(ievent.nick, \
189 "[%s] %s" % (ievent.nick, ievent.txt))
190
191 self.privwait.check(ievent)
192 except socket.error, ex:
193 try:
194 (errno, errstr) = ex
195 except:
196 errno = 0
197 errstr = str(ex)
198 if errno == 35 or errno == 11:
199 continue
200 except Exception, ex:
201 handle_exception()
202 sockfile.close()
203 rlog(1, self.name, 'closing dcc with ' + nick)
204
206 """ connect to dcc request from nick """
207 try:
208 port = int(port)
209 if re.search(':', addr):
210 rlog(1, self.name, 'creating ipv6 socket for dcc chat with %s'\
211 % nick)
212 sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
213 sock.connect((addr, port))
214 else:
215 rlog(1, self.name, 'creating ipv4 socket for dcc chat with %s'\
216 % nick)
217 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
218 sock.connect((addr, port))
219 except Exception, ex:
220 rlog(10 , self.name, 'dcc error: %s' % str(ex))
221 return
222
223 self._dodcc(sock, nick, userhost)
224
229
231 """ join channels """
232 for i in self.state['joinedchannels']:
233 try:
234 key = self.channels.getkey(i)
235 rlog(10, self.name, 'join %s' % i.split()[0])
236 self.join(i, key)
237 except Exception, ex:
238 rlog(10, self.name, 'failed to join %s: %s' % (i, str(ex)))
239
241 for i in self.state['joinedchannels']:
242 self.say(i, txt)
243
244 - def send(self, txt):
245 """ call Irc send and check for monitor callbacks """
246 Irc.send(self, str(txt))
247 outmonitor.put(self, str(txt))
248
254
256 """ stop the bot """
257 self.stopped = 1
258
259 rlog(10, self.name, 'stopped')
260
262 """ save data, quit the bot and do shutdown """
263 if self.connectok.isSet():
264 try:
265 self._raw('QUIT :%s' % config['quitmsg'])
266 except IOError:
267 pass
268 self.stop()
269 partyline.stop(self)
270 Irc.exit(self)
271
272 self.save()
273 rlog(10, self.name, 'exit')
274 return 1
275
277 """ send MODE request for channel """
278 if not channel:
279 return
280 self.send('MODE %s' % channel)
281
282 - def join(self, channel, password=None):
283 """ join a channel .. use optional password """
284 result = Irc.join(self, channel, password)
285 if result != 1:
286 return result
287 if not self.channels.