1
2
3
4
5 """ jabber bot definition """
6
7 __copyright__ = 'this file is in the public domain'
8 __revision__ = '$Id: bot.py 75 2005-09-12 16:33:00Z bart $'
9
10 from gozerbot.users import users
11 from gozerbot.monitor import jabbermonitor
12 from gozerbot.wait import Jabberwait, Jabbererrorwait
13 from gozerbot.generic import rlog, handle_exception, lockdec, waitforqueue, \
14 toenc, fromenc, jabberstrip
15 from gozerbot.config import config
16 from gozerbot.plugins import plugins
17 from gozerbot.jabbermsg import Jabbermsg
18 from gozerbot.jabberpresence import Jabberpresence
19 from gozerbot.pdod import Pdod
20 from gozerbot.dol import Dol
21 from gozerbot.datadir import datadir
22 from gozerbot.channels import Channels
23 from gozerbot.less import Less
24 from gozerbot.ignore import shouldignore
25 from gozerbot.callbacks import jcallbacks
26 from gozerbot.thr import start_new_thread
27 from gozerbot.fleet import fleet
28 from gozerbot.botbase import BotBase
29 from xmpp.simplexml import Node
30 import xmpp, time, Queue, os, threading, thread, types, xml
31
32 jabberoutlock = thread.allocate_lock()
33 jabberinlock = thread.allocate_lock()
34 outlocked = lockdec(jabberoutlock)
35 inlocked = lockdec(jabberinlock)
38
39 """ jabber bot class """
40
41 - def __init__(self, name='jabbermain', owner=[]):
42 BotBase.__init__(self, name, owner)
43 self.type = 'jabber'
44 self.outqueue = Queue.Queue()
45 self.host = None
46 self.user = None
47 self.sock = None
48 self.jid = None
49 self.username = None
50 self.me = None
51 self.server = None
52 self.lastin = None
53 self.test = 0
54 self.connecttime = 0
55 self.connection = None
56 self.privwait = Jabberwait()
57 self.errorwait = Jabbererrorwait()
58 self.jabber = True
59 self.connectok = threading.Event()
60 self.jids = {}
61 self.topics = {}
62 self.timejoined = {}
63 if not self.state.has_key('ratelimit'):
64 self.state['ratelimit'] = 0.05
65
67 self.exit()
68 return {self.name: [self.host, self.user, self.password, self.port]}
69
71 """ process loop """
72 while not self.stopped:
73 try:
74 time.sleep(0.001)
75 res = self.connection.Process()
76 if res:
77 self.lastin = time.time()
78 except xmpp.StreamError, ex:
79 if u'Disconnected' in str(ex):
80 rlog(10, self.name, str(ex))
81 self.reconnect()
82 except xml.parsers.expat.ExpatError, ex:
83 if u'not well-formed' in str(ex):
84 rlog(10, self.name, str(ex))
85 continue
86 except Exception, ex:
87 if not self.stopped:
88 handle_exception()
89 time.sleep(2)
90 else:
91 return
92
94 rlog(10, self.name, 'starting outputloop')
95 while not self.stopped:
96 what = self.outqueue.get()
97 if self.stopped or what == None:
98 break
99 self.rawsend(what)
100 sleeptime = config['jabberoutsleep']
101 if sleeptime:
102 time.sleep(sleeptime)
103 else:
104 time.sleep(0.1)
105 rlog(10, self.name, 'stopping outputloop')
106
108 """ keepalive method .. send empty string to self every 3 minutes """
109 nrsec = 0
110 while not self.stopped:
111 time.sleep(1)
112 nrsec += 1
113 if nrsec < 180:
114 continue
115 else:
116 nrsec = 0
117 self.say(self.me, "")
118
120 """ channels keep alive method """
121 nrsec = 0
122 while not self.stopped:
123 time.sleep(1)
124 nrsec += 1
125 if nrsec < 600:
126 continue
127 for i in self.state['joinedchannels']:
128 self.say(i, "")
129
130 - def _connect(self, host, user, password, port=5222):
131 """ connect to server .. start read loop """
132 self.host = host
133 self.port = port
134 self.user = user
135 self.password = password
136 if not '@' in user:
137 rlog(100, self.name, 'user needs to be in username@host format')
138 return
139 self.username = user.split('@')[0]
140 self.me = user
141 self.jid = xmpp.JID(user)
142 self.server = self.jid.getDomain()
143 self.nick = self.username
144 self.password = password
145 rlog(10, self.name, 'connecting to %s' % self.host)
146
147 self.connection = xmpp.Client(self.server, debug=[])
148 try:
149 self.connection.connect((self.host, self.port))
150 except AttributeError:
151 rlog(10, self.name, "can't connect to %s" % self.host)
152 return
153 if not self.connection:
154 rlog(10, self.name, "can't connect to %s" % self.host)
155 return
156 rlog(10, self.name, 'doing auth')
157 auth = self.connection.auth(self.username, self.password, \
158 'gozerbot')
159 if not auth:
160 rlog(10, self.name, 'auth for %s failed .. trying register' \
161 % self.username)
162 info = {'username': self.username, 'password': self.password}
163 xmpp.features.getRegInfo(self.connection, self.host, info)
164 if not xmpp.features.register(self.connection, self.host, info):
165 rlog(100, self.name, "can't register")
166 return
167 else:
168 self.connection = xmpp.Client(self.server, debug=[])
169 self.connection.connect((self.host, self.port))
170 auth = self.connection.auth(self.username, self.password, \
171 'gozerbot')
172 rlog(100, self.name, "register succeded")
173 self.connecttime = time.time()
174 rlog(100, self.name, 'connected! type: %s' % \
175 self.connection.connected)
176 self.connection.RegisterHandler('message', self.messageHandler)
177 self.connection.RegisterHandler('presence', self.presenceHandler)
178 self.connection.RegisterHandler('iq', self.iqHandler)
179 self.connection.UnregisterDisconnectHandler(\
180 self.connection.DisconnectHandler)
181 self.connection.RegisterDisconnectHandler(self.disconnectHandler)
182 self.connection.UnregisterHandlerOnce = self.UnregisterHandlerOnce
183 self.stopped = 0
184 jabbermonitor.start()
185 start_new_thread(self._doprocess, ())
186 start_new_thread(self._keepalive, ())
187 start_new_thread(self._outputloop, ())
188
189 self.connection.sendInitPresence()
190 self.connection.getRoster()
191 self.connectok.set()
192 return 1
193
194 - def connect(self, host, user, password, port=5222, ipv6=None, ssl=None, \
195 reconnect=True):
196
197 res = 0
198 try:
199 res = self._connect(host, user, password, port)
200
201
202
203 except Exception, ex:
204 if self.stopped:
205 return 0
206 rlog(10, self.name, str(ex))
207
208 if reconnect:
209 return self.reconnect()
210 if res and not fleet.byname(self.name):
211 fleet.addbot(self)
212 return res
213
215 """ join channels """
216 time.sleep(5)
217 for i in self.state['joinedchannels']:
218 key = self.channels.getkey(i)
219 nick = self.channels.getnick(i)
220 result = self.join(i, key, nick)
221 if result == 1:
222 rlog(10, self.name, 'joined %s' % i)
223 else:
224 rlog(10, self.name, 'failed to join %s: %s' % (i, result))
225
226
228 for i in self.state['joinedchannels']:
229 self.say(i, txt)
230
232 """ send presence """
233 presence = xmpp.Presence(to=to)
234 presence.setFrom(self.me)
235 self.send(presence)
236
237
239 """ handle iq stanza's """
240 rlog(2, self.name + '-Iq', str(node))
241 node.cmnd = 'Iq'
242 node.conn = conn
243 jcallbacks.check(self, node)
244
246 """ message handler """
247 if self.test:
248 return
249 if 'jabber:x:delay' in str(msg):
250 return
251 m = Jabbermsg(msg)
252 m.toirc(self)
253 if m.groupchat and m.getSubject():
254 self.topiccheck(m)
255 return
256 if self.privwait.check(m):
257 return
258 if not m.txt:
259 return
260 if self.me in m.userhost:
261 return 0
262 if m.groupchat and self.nick == m.resource:
263 return 0
264 go = 1
265 try:
266 cc = self.channels[m.channel]['cc']
267 except (TypeError, KeyError):
268 cc = config['defaultcc'] or '!'
269 try:
270 channick = self.channels[m.channel]['nick']
271 except (TypeError, KeyError):
272 channick = self.nick
273 if m.groupchat and not m.txt[0] in cc:
274 go = 0
275 if m.txt.startswith("%s: " % channick):
276 m.txt = m.txt.replace("%s: " % channick, "")
277 go = 1
278 elif m.txt.startswith("%s, " % channick):
279 m.txt = m.txt.replace("%s, " % channick, "")
280 go = 1
281 if m.txt[0] in cc:
282 m.txt = m.txt[1:]
283 if go and not 'dojcoll' in str(m.id):
284 try:
285