Package gozerbot :: Module bot
[hide private]
[frames] | no frames]

Source Code for Module gozerbot.bot

  1  # gozerbot/bot.py 
  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   
35 -class Bot(Irc):
36 37 """ class that dispatches commands and checks for callbacks to fire """ 38
39 - def __init__(self, name = 'main', owner=[]):
40 self.debug = False 41 Irc.__init__(self, name, owner) 42 # object used to wait for PRIVMSG 43 self.privwait = Privwait() 44 # channels where we are op 45 if not self.state.has_key('opchan'): 46 self.state['opchan'] = [] 47 # nicks of splitted users 48 self.splitted = [] 49 self.userchannels = Dol() 50 outmonitor.start() 51 runners_start()
52
53 - def __str__(self):
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
57 - def _resume(self, data, reto):
58 if not Irc._resume(self, data, reto): 59 return 0 60 for i in self.state['joinedchannels']: 61 start_new_thread(self.who, (i, )) 62 return 1
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
70 - def _dcclisten(self, nick, userhost, channel):
71 """ accept dcc chat requests """ 72 try: 73 # get listen socket on host were running on 74 listenip = socket.gethostbyname(socket.gethostname()) 75 (port, listensock) = getlistensocket(listenip) 76 # convert ascii ip to netwerk 32 bit 77 ipip2 = socket.inet_aton(listenip) 78 ipip = struct.unpack('>L', ipip2)[0] 79 # send dcc chat request 80 chatmsg = 'DCC CHAT CHAT %s %s' % (ipip, port) 81 self.ctcp(nick, chatmsg) 82 # go listen to response 83 sock = listensock.accept()[0] 84 except Exception, ex: 85 rlog(10 , self.name, 'dcc error: %s' % str(ex)) 86 return 87 # connected 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 # send welcome message .. show list of commands for USER perms 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 # add joined user to the partyline 113 partyline.add_party(self, sock, nick, userhost, channel) 114 while 1: 115 time.sleep(0.001) 116 try: 117 # read from socket 118 res = sockfile.readline() 119 # if res == "" than the otherside had disconnected 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 # skip on timeout 126 continue 127 except socket.error, ex: 128 # handle socket errors .. skip on errno 35 and 11 temp unavail 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 # other exception occured .. close connection 140 handle_exception() 141 rlog(10, self.name, 'closing dcc with ' + nick) 142 partyline.del_party(nick) 143 return 144 try: 145 # see if user provided channel 146 res = strippedtxt(res.strip()) 147 chan = checkchan(self, res) 148 if chan != None: 149 (channel, res) = chan 150 else: 151 channel = '' 152 # create ircevent 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 # check if its a command if so dispatch 164 if ievent.txt[0] == "!": 165 ievent.txt = ievent.txt[1:] 166 plugins.trydispatch(self, ievent) 167 continue 168 elif ievent.txt[0] == "@": 169 # command is broadcast so send response to the paryline 170 # members 171 partyline.say_broadcast_notself(ievent.nick, \ 172 "[%s] %s" % (ievent.nick, ievent.txt)) 173 # make queue and run trydispatch to see if command has 174 # fired 175 q = Queue.Queue() 176 ievent.queues = [q] 177 ievent.txt = ievent.txt[1:] 178 plugins.trydispatch(self, ievent) 179 # wait for result .. default timeout is 10 sec 180 result = waitforqueue(q, 5) 181 if result: 182 # broadcast result 183 for i in result: 184 partyline.say_broadcast("[bot] %s" % i) 185 continue 186 else: 187 # not a command so send txt to partyline 188 partyline.say_broadcast_notself(ievent.nick, \ 189 "[%s] %s" % (ievent.nick, ievent.txt)) 190 # check PRIVMSG wait 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
205 - def _dccconnect(self, nick, userhost, addr, port):
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 # were connected .. start dcc loop 223 self._dodcc(sock, nick, userhost)
224
225 - def reconnect(self):
226 """ reconnect and if succesfull join channels """ 227 if Irc.reconnect(self): 228 self.joinchannels()
229
230 - def joinchannels(self):
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
240 - def broadcast(self, txt):
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
249 - def save(self):
250 """ saves channels and state """ 251 self.channels.save() 252 self.userhosts.save() 253 Irc.save(self)
254
255 - def stop(self):
256 """ stop the bot """ 257 self.stopped = 1 258 # shut down handlers 259 rlog(10, self.name, 'stopped')
260
261 - def exit(self):
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 #self.shutdown() 272 self.save() 273 rlog(10, self.name, 'exit') 274 return 1
275
276 - def getchannelmode(self, channel):
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.