source file: p10/connection.py
file stats: 872 lines, 794 executed: 91.1% covered
1. #!/usr/bin/env python
2.
3. # Things that aren't implemented:
4. # * RPING
5. # * RPONG
6. # * ASLL
7. # * UPING
8. # * WHOWAS
9.
10. #import threading
11. import asyncore
12. import socket
13. import fnmatch
14.
15. import base64
16. import parser
17. import commands.account
18. import commands.admin
19. import commands.asll
20. import commands.away
21. import commands.burst
22. import commands.clearmode
23. import commands.connect
24. import commands.create
25. import commands.destruct
26. import commands.end_of_burst
27. import commands.eob_ack
28. import commands.error
29. import commands.gline
30. import commands.info
31. import commands.invite
32. import commands.join
33. import commands.jupe
34. import commands.kick
35. import commands.kill
36. import commands.links
37. import commands.lusers
38. import commands.mode
39. import commands.motd
40. import commands.names
41. import commands.nick
42. import commands.notice
43. import commands.numberrelay
44. import commands.part
45. import commands.password
46. import commands.ping
47. import commands.pong
48. import commands.privmsg
49. import commands.quit
50. import commands.rping
51. import commands.rpong
52. import commands.server
53. import commands.settime
54. import commands.silence
55. import commands.squit
56. import commands.stats
57. import commands.svsjoin
58. import commands.svsnick
59. import commands.time
60. import commands.topic
61. import commands.trace
62. import commands.uping
63. import commands.version
64. import commands.wallchops
65. import commands.wallops
66. import commands.wallusers
67. import commands.wallvoices
68. import commands.whois
69. import commands.whowas
70.
71. class connection(asyncore.dispatcher):
72. """ Represents a connection upstream """
73.
74. _state = None
75. connstate = None
76. _parser = None
77. numeric = None
78. _endpoint = None
79. _password = None
80. _upstream_password = None
81. _buffer = ""
82. _data = ""
83. _last_pong = 0
84.
85. DISCONNECTED = 0
86. CONNECTED = 1
87. CHALLENGED = 2
88. HANDSHAKE = 3
89. AUTHENTICATED = 4
90. COMPLETE = 5
91.
92. def __init__(self, state):
93. """ Sets up the state that this connection will alter """
94. asyncore.dispatcher.__init__(self)
95. self._state = state
96. self.connstate = self.DISCONNECTED
97. self.numeric = None
98. self._upstream_password = None
99. self._password = None
100. self._endpoint = None
101. self._parser = parser.parser(state.maxClientNumerics)
102. self._buffer = ""
103. self._data = ""
104. self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
105.
106. def start(self, endpoint, password):
107. # Create our socket
108. self._endpoint = endpoint
109. self._password = password
110. self._connect()
111. return self
112.
113. def _connect(self):
114. self.connect(self._endpoint)
115. self.connstate = self.CONNECTED
116.
117. # Send pass and server - don't use the parser at this point
118. self._buffer += "PASS :" + self._password + "\r\n"
119. self._buffer += "SERVER " + self._state.getServerName() + " 1 " + str(self._state.ts()) + " " + str(self._state.ts()) + " J10 " + base64.createNumeric((self._state.getServerID(), 262143)) + " +s :" + self._state.getServerDescription() + "\r\n"
120. self.connstate = self.CHALLENGED
121.
122. # Set up stuff for authentication
123. self._parser.registerHandler("PASS", commands.password.password(self._state, self))
124. self._parser.registerHandler("ERROR", commands.error.error(self._state))
125. self._last_pong = self._state.ts()
126. self._last_ping = self._state.ts()
127.
128. def _setupCallbacks(self):
129. self._state.registerCallback(self._state.CALLBACK_NEWUSER, self.callbackNewUser)
130. self._state.registerCallback(self._state.CALLBACK_CHANGENICK, self.callbackChangeNick)
131. self._state.registerCallback(self._state.CALLBACK_NEWSERVER, self.callbackNewServer)
132. self._state.registerCallback(self._state.CALLBACK_AUTHENTICATE, self.callbackAuthenticate)
133. self._state.registerCallback(self._state.CALLBACK_USERMODECHANGE, self.callbackChangeUserMode)
134. self._state.registerCallback(self._state.CALLBACK_AWAY, self.callbackAway)
135. self._state.registerCallback(self._state.CALLBACK_BACK, self.callbackBack)
136. self._state.registerCallback(self._state.CALLBACK_CHANNELCREATE, self.callbackChannelCreate)
137. self._state.registerCallback(self._state.CALLBACK_CHANNELJOIN, self.callbackChannelJoin)
138. self._state.registerCallback(self._state.CALLBACK_CHANNELPART, self.callbackChannelPart)
139. self._state.registerCallback(self._state.CALLBACK_CHANNELPARTALL, self.callbackPartAll)
140. self._state.registerCallback(self._state.CALLBACK_CHANNELMODECHANGE, self.callbackChannelChangeMode)
141. self._state.registerCallback(self._state.CALLBACK_CHANNELBANADD, self.callbackChannelAddBan)
142. self._state.registerCallback(self._state.CALLBACK_CHANNELBANREMOVE, self.callbackChannelRemoveBan)
143. self._state.registerCallback(self._state.CALLBACK_CHANNELBANCLEAR, self.callbackChannelClearBans)
144. self._state.registerCallback(self._state.CALLBACK_CHANNELOP, self.callbackChannelOp)
145. self._state.registerCallback(self._state.CALLBACK_CHANNELDEOP, self.callbackChannelDeop)
146. self._state.registerCallback(self._state.CALLBACK_CHANNELCLEAROPS, self.callbackChannelClearOps)
147. self._state.registerCallback(self._state.CALLBACK_CHANNELVOICE, self.callbackChannelVoice)
148. self._state.registerCallback(self._state.CALLBACK_CHANNELDEVOICE, self.callbackChannelDevoice)
149. self._state.registerCallback(self._state.CALLBACK_CHANNELCLEARVOICES, self.callbackChannelClearVoices)
150. self._state.registerCallback(self._state.CALLBACK_GLINEADD, self.callbackGlineAdd)
151. self._state.registerCallback(self._state.CALLBACK_GLINEREMOVE, self.callbackGlineRemove)
152. self._state.registerCallback(self._state.CALLBACK_INVITE, self.callbackInvite)
153. self._state.registerCallback(self._state.CALLBACK_JUPEADD, self.callbackJupeAdd)
154. self._state.registerCallback(self._state.CALLBACK_JUPEREMOVE, self.callbackJupeRemove)
155. self._state.registerCallback(self._state.CALLBACK_REQUESTADMIN, self.callbackAdminInfo)
156. self._state.registerCallback(self._state.CALLBACK_REQUESTINFO, self.callbackInfoRequest)
157. self._state.registerCallback(self._state.CALLBACK_CHANNELKICK, self.callbackKick)
158. self._state.registerCallback(self._state.CALLBACK_CHANNELPARTZOMBIE, self.callbackZombiePart)
159. self._state.registerCallback(self._state.CALLBACK_CHANNELDESTROY, self.callbackChannelDestroy)
160. self._state.registerCallback(self._state.CALLBACK_QUIT, self.callbackQuit)
161. self._state.registerCallback(self._state.CALLBACK_KILL, self.callbackKill)
162. self._state.registerCallback(self._state.CALLBACK_REQUESTLUSERS, self.callbackLusers)
163. self._state.registerCallback(self._state.CALLBACK_REQUESTLINKS, self.callbackLinks)
164. self._state.registerCallback(self._state.CALLBACK_REQUESTMOTD, self.callbackMOTD)
165. self._state.registerCallback(self._state.CALLBACK_REQUESTNAMES, self.callbackNames)
166. self._state.registerCallback(self._state.CALLBACK_CHANNELTOPIC, self.callbackTopic)
167. self._state.registerCallback(self._state.CALLBACK_SILENCEADD, self.callbackSilenceAdd)
168. self._state.registerCallback(self._state.CALLBACK_SILENCEREMOVE, self.callbackSilenceRemove)
169. self._state.registerCallback(self._state.CALLBACK_SERVERQUIT, self.callbackSquit)
170. self._state.registerCallback(self._state.CALLBACK_REQUESTVERSION, self.callbackRequestVersion)
171. self._state.registerCallback(self._state.CALLBACK_REQUESTSTATS, self.callbackRequestStats)
172. self._state.registerCallback(self._state.CALLBACK_TRACE, self.callbackTrace)
173. self._state.registerCallback(self._state.CALLBACK_PING, self.callbackPing)
174. self._state.registerCallback(self._state.CALLBACK_PONG, self.callbackPong)
175. self._state.registerCallback(self._state.CALLBACK_REQUESTWHOIS, self.callbackRequestWhois)
176. self._state.registerCallback(self._state.CALLBACK_PRIVMSG, self.callbackPrivmsg)
177. self._state.registerCallback(self._state.CALLBACK_OOBMSG, self.callbackOobmsg)
178. self._state.registerCallback(self._state.CALLBACK_NOTICE, self.callbackNotice)
179. self._state.registerCallback(self._state.CALLBACK_WALLOPS, self.callbackWallops)
180. self._state.registerCallback(self._state.CALLBACK_WALLUSERS, self.callbackWallusers)
181. self._state.registerCallback(self._state.CALLBACK_WALLVOICES, self.callbackWallvoices)
182. self._state.registerCallback(self._state.CALLBACK_WALLCHOPS, self.callbackWallchops)
183.
184. def _teardownCallbacks(self):
185. self._state.deregisterCallback(self._state.CALLBACK_NEWUSER, self.callbackNewUser)
186. self._state.deregisterCallback(self._state.CALLBACK_CHANGENICK, self.callbackChangeNick)
187. self._state.deregisterCallback(self._state.CALLBACK_NEWSERVER, self.callbackNewServer)
188. self._state.deregisterCallback(self._state.CALLBACK_AUTHENTICATE, self.callbackAuthenticate)
189. self._state.deregisterCallback(self._state.CALLBACK_USERMODECHANGE, self.callbackChangeUserMode)
190. self._state.deregisterCallback(self._state.CALLBACK_AWAY, self.callbackAway)
191. self._state.deregisterCallback(self._state.CALLBACK_BACK, self.callbackBack)
192. self._state.deregisterCallback(self._state.CALLBACK_CHANNELCREATE, self.callbackChannelCreate)
193. self._state.deregisterCallback(self._state.CALLBACK_CHANNELJOIN, self.callbackChannelJoin)
194. self._state.deregisterCallback(self._state.CALLBACK_CHANNELPART, self.callbackChannelPart)
195. self._state.deregisterCallback(self._state.CALLBACK_CHANNELPARTALL, self.callbackPartAll)
196. self._state.deregisterCallback(self._state.CALLBACK_CHANNELMODECHANGE, self.callbackChannelChangeMode)
197. self._state.deregisterCallback(self._state.CALLBACK_CHANNELBANADD, self.callbackChannelAddBan)
198. self._state.deregisterCallback(self._state.CALLBACK_CHANNELBANREMOVE, self.callbackChannelRemoveBan)
199. self._state.deregisterCallback(self._state.CALLBACK_CHANNELBANCLEAR, self.callbackChannelClearBans)
200. self._state.deregisterCallback(self._state.CALLBACK_CHANNELOP, self.callbackChannelOp)
201. self._state.deregisterCallback(self._state.CALLBACK_CHANNELDEOP, self.callbackChannelDeop)
202. self._state.deregisterCallback(self._state.CALLBACK_CHANNELCLEAROPS, self.callbackChannelClearOps)
203. self._state.deregisterCallback(self._state.CALLBACK_CHANNELVOICE, self.callbackChannelVoice)
204. self._state.deregisterCallback(self._state.CALLBACK_CHANNELDEVOICE, self.callbackChannelDevoice)
205. self._state.deregisterCallback(self._state.CALLBACK_CHANNELCLEARVOICES, self.callbackChannelClearVoices)
206. self._state.deregisterCallback(self._state.CALLBACK_GLINEADD, self.callbackGlineAdd)
207. self._state.deregisterCallback(self._state.CALLBACK_GLINEREMOVE, self.callbackGlineRemove)
208. self._state.deregisterCallback(self._state.CALLBACK_INVITE, self.callbackInvite)
209. self._state.deregisterCallback(self._state.CALLBACK_JUPEADD, self.callbackJupeAdd)
210. self._state.deregisterCallback(self._state.CALLBACK_JUPEREMOVE, self.callbackJupeRemove)
211. self._state.deregisterCallback(self._state.CALLBACK_REQUESTADMIN, self.callbackAdminInfo)
212. self._state.deregisterCallback(self._state.CALLBACK_REQUESTINFO, self.callbackInfoRequest)
213. self._state.deregisterCallback(self._state.CALLBACK_CHANNELKICK, self.callbackKick)
214. self._state.deregisterCallback(self._state.CALLBACK_CHANNELPARTZOMBIE, self.callbackZombiePart)
215. self._state.deregisterCallback(self._state.CALLBACK_CHANNELDESTROY, self.callbackChannelDestroy)
216. self._state.deregisterCallback(self._state.CALLBACK_QUIT, self.callbackQuit)
217. self._state.deregisterCallback(self._state.CALLBACK_KILL, self.callbackKill)
218. self._state.deregisterCallback(self._state.CALLBACK_REQUESTLUSERS, self.callbackLusers)
219. self._state.deregisterCallback(self._state.CALLBACK_REQUESTLINKS, self.callbackLinks)
220. self._state.deregisterCallback(self._state.CALLBACK_REQUESTMOTD, self.callbackMOTD)
221. self._state.deregisterCallback(self._state.CALLBACK_REQUESTNAMES, self.callbackNames)
222. self._state.deregisterCallback(self._state.CALLBACK_CHANNELTOPIC, self.callbackTopic)
223. self._state.deregisterCallback(self._state.CALLBACK_SILENCEADD, self.callbackSilenceAdd)
224. self._state.deregisterCallback(self._state.CALLBACK_SILENCEREMOVE, self.callbackSilenceRemove)
225. self._state.deregisterCallback(self._state.CALLBACK_SERVERQUIT, self.callbackSquit)
226. self._state.deregisterCallback(self._state.CALLBACK_REQUESTVERSION, self.callbackRequestVersion)
227. self._state.deregisterCallback(self._state.CALLBACK_REQUESTSTATS, self.callbackRequestStats)
228. self._state.deregisterCallback(self._state.CALLBACK_TRACE, self.callbackTrace)
229. self._state.deregisterCallback(self._state.CALLBACK_PING, self.callbackPing)
230. self._state.deregisterCallback(self._state.CALLBACK_PONG, self.callbackPong)
231. self._state.deregisterCallback(self._state.CALLBACK_REQUESTWHOIS, self.callbackRequestWhois)
232. self._state.deregisterCallback(self._state.CALLBACK_PRIVMSG, self.callbackPrivmsg)
233. self._state.deregisterCallback(self._state.CALLBACK_OOBMSG, self.callbackOobmsg)
234. self._state.deregisterCallback(self._state.CALLBACK_NOTICE, self.callbackNotice)
235. self._state.deregisterCallback(self._state.CALLBACK_WALLOPS, self.callbackWallops)
236. self._state.deregisterCallback(self._state.CALLBACK_WALLUSERS, self.callbackWallusers)
237. self._state.deregisterCallback(self._state.CALLBACK_WALLVOICES, self.callbackWallvoices)
238. self._state.deregisterCallback(self._state.CALLBACK_WALLCHOPS, self.callbackWallchops)
239.
240. def _setupParser(self):
241. p = self._parser
242. p.registerHandler("AC", commands.account.account(self._state))
243. p.registerHandler("AD", commands.admin.admin(self._state))
244. p.registerHandler("LL", commands.asll.asll(self._state))
245. p.registerHandler("A", commands.away.away(self._state))
246. p.registerHandler("B", commands.burst.burst(self._state))
247. p.registerHandler("CM", commands.clearmode.clearmode(self._state))
248. p.registerHandler("CO", commands.connect.connect(self._state))
249. p.registerHandler("C", commands.create.create(self._state))
250. p.registerHandler("DE", commands.destruct.destruct(self._state))
251. p.registerHandler("DS", commands.wallops.wallops(self._state))
252. p.registerHandler("EB", commands.end_of_burst.end_of_burst(self._state, self))
253. p.registerHandler("EA", commands.eob_ack.eob_ack(self._state))
254. p.registerHandler("Y", commands.error.error(self._state))
255. p.registerHandler("GL", commands.gline.gline(self._state))
256. p.registerHandler("F", commands.info.info(self._state))
257. p.registerHandler("I", commands.invite.invite(self._state))
258. p.registerHandler("J", commands.join.join(self._state))
259. p.registerHandler("JU", commands.jupe.jupe(self._state))
260. p.registerHandler("K", commands.kick.kick(self._state))
261. p.registerHandler("D", commands.kill.kill(self._state))
262. p.registerHandler("LI", commands.links.links(self._state))
263. p.registerHandler("LU", commands.lusers.lusers(self._state))
264. p.registerHandler("M", commands.mode.mode(self._state))
265. p.registerHandler("MO", commands.motd.motd(self._state))
266. p.registerHandler("E", commands.names.names(self._state))
267. p.registerHandler("N", commands.nick.nick(self._state))
268. p.registerHandler("O", commands.notice.notice(self._state))
269. p.registerHandler("OM", commands.mode.mode(self._state)) # opmodes get handled exactly the same as normal modes
270. p.registerHandler("L", commands.part.part(self._state))
271. p.registerHandler("G", commands.ping.ping(self._state, self))
272. p.registerHandler("Z", commands.pong.pong(self._state, self))
273. p.registerHandler("P", commands.privmsg.privmsg(self._state))
274. p.registerHandler("Q", commands.quit.quit(self._state))
275. #p.registerHandler("RI", commands.rping.rping(self._state))
276. #p.registerHandler("RO", commands.rpong.rpong(self._state))
277. p.registerHandler("S", commands.server.server(self._state, None))
278. p.registerHandler("SE", commands.settime.settime(self._state))
279. p.registerHandler("U", commands.silence.silence(self._state))
280. p.registerHandler("SQ", commands.squit.squit(self._state))
281. p.registerHandler("R", commands.stats.stats(self._state))
282. p.registerHandler("SJ", commands.svsjoin.svsjoin(self._state))
283. p.registerHandler("SN", commands.svsnick.svsnick(self._state))
284. p.registerHandler("TI", commands.time.time(self._state))
285. p.registerHandler("T", commands.topic.topic(self._state))
286. p.registerHandler("TR", commands.trace.trace(self._state))
287. p.registerHandler("UP", commands.uping.uping(self._state))
288. p.registerHandler("V", commands.version.version(self._state))
289. p.registerHandler("WC", commands.wallchops.wallchops(self._state))
290. p.registerHandler("WA", commands.wallops.wallops(self._state))
291. p.registerHandler("WU", commands.wallusers.wallusers(self._state))
292. p.registerHandler("WV", commands.wallvoices.wallvoices(self._state))
293. p.registerHandler("W", commands.whois.whois(self._state))
294. p.registerHandler("X", commands.whowas.whowas(self._state))
295. p.registerHandler("252", commands.numberrelay.numberrelay(self._state, "252"))
296. p.registerHandler("254", commands.numberrelay.numberrelay(self._state, "254"))
297. p.registerHandler("255", commands.numberrelay.numberrelay(self._state, "255"))
298. p.registerHandler("256", commands.numberrelay.numberrelay(self._state, "256"))
299. p.registerHandler("257", commands.numberrelay.numberrelay(self._state, "257"))
300. p.registerHandler("258", commands.numberrelay.numberrelay(self._state, "258"))
301. p.registerHandler("259", commands.numberrelay.numberrelay(self._state, "259"))
302. p.registerHandler("351", commands.numberrelay.numberrelay(self._state, "351"))
303. p.registerHandler("353", commands.numberrelay.numberrelay(self._state, "353"))
304. p.registerHandler("364", commands.numberrelay.numberrelay(self._state, "364"))
305. p.registerHandler("365", commands.numberrelay.numberrelay(self._state, "365"))
306. p.registerHandler("366", commands.numberrelay.numberrelay(self._state, "366"))
307. p.registerHandler("371", commands.numberrelay.numberrelay(self._state, "371"))
308. p.registerHandler("374", commands.numberrelay.numberrelay(self._state, "374"))
309. p.registerHandler("375", commands.numberrelay.numberrelay(self._state, "375"))
310. p.registerHandler("376", commands.numberrelay.numberrelay(self._state, "376"))
311.
312. def _sendLine(self, source_client, token, args):
313. """ Send a line upsteam
314.
315. source_client: An integer, or None, representing which client is sending this message
316. token: The token to be sent.
317. args: An array of strings making up the message body """
318. self._buffer += self._parser.build(source_client, token, args)
319.
320. def registerNumeric(self, numeric):
321. self.numeric = numeric
322.
323. def registerUpstreamPassword(self, password):
324. self._upstream_password = password
325.
326. def registerEOB(self):
327. self._sendLine((self._state.getServerID(), None), "EA", [])
328.
329. def registerPing(self, arg):
330. self._sendLine((self._state.getServerID(), None), "Z", [base64.createNumeric((self._state.getServerID(), None)), arg])
331.
332. def registerPong(self):
333. self._last_pong = self._state.ts()
334.
335. def close_connection(self):
336. self.close()
337. self.connstate = self.COMPLETE
338.
339. def do_ping(self):
340. # Give a 60 second grace between ping being sent and timing out
341. if (self._state.ts() - 60) > self._last_ping and self._last_ping > self._last_pong:
342. self.error("Ping Timeout")
343. elif self._last_ping < (self._state.ts() - 180):
344. self._sendLine((self._state.getServerID(), None), "G", [base64.createNumeric((self._state.getServerID(), None))])
345. self._last_ping = self._state.ts()
346.
347. def error(self, reason):
348. """ TODO: Handles errors on the connection """
349. print "ERROR: " + reason
350. self._sendLine((self._state.getServerID(), None), "Y", [reason])
351.
352. def __recursiveBurstServer(self, server):
353. # We don't burst ourselves
354. if self._state.servers[server].numeric != self._state.getServerID():
355. self.callbackNewServer(((self._state.servers[server].origin, None),
356. self._state.servers[server].numeric,
357. self._state.servers[server].name,
358. self._state.servers[server].maxclient,
359. self._state.servers[server].boot_ts,
360. self._state.servers[server].link_ts,
361. self._state.servers[server].protocol,
362. self._state.servers[server].hops,
363. self._state.servers[server].flags,
364. self._state.servers[server].description))
365. for child in self._state.servers[server].children:
366. # Don't burst the server back to us
367. if child != self.numeric:
368. self.__recursiveBurstServer(child)
369.
370. def _sendBurst(self):
371. # Now we start listening
372. self._setupCallbacks()
373.
374. # Send servers
375. self.__recursiveBurstServer(self._state.getServerID())
376.
377. # Send g-lines
378. for (mask, description, expires, active, mod_time) in self._state.glines():
379. if active:
380. self.callbackGlineAdd(((self._state.getServerID(), None), mask, None, expires, description))
381. else:
382. self.callbackGlineRemove(((self._state.getServerID(), None), mask, None))
383.
384. # Send jupes
385. for (mask, description, expires, active, mod_time) in self._state.jupes():
386. if active:
387. self.callbackJupeAdd(((self._state.getServerID(), None), mask, None, expires, description))
388. else:
389. self.callbackJupeRemove(((self._state.getServerID(), None), mask, None))
390.
391. # Send users
392. for user in self._state.users:
393. self.callbackNewUser(( (self._state.users[user].numeric[0], None),
394. self._state.users[user].numeric,
395. self._state.users[user].nickname,
396. self._state.users[user].username,
397. self._state.users[user].hostname,
398. self._state.users[user].modes(),
399. self._state.users[user].ip,
400. self._state.users[user].hops,
401. self._state.users[user].ts,
402. self._state.users[user].fullname))
403.
404. # Send channels
405. for channel in self._state.channels:
406.
407. # First part of burst
408. burst = [channel, str(self._state.channels[channel].ts)]
409.
410. # Channel modes
411. (modestr, modeargs) = self._buildModeString(self._state.channels[channel].modes())
412.
413. if modestr != "":
414. burst.append(modestr)
415. burst += modeargs
416.
417. # Get users on channel
418. users = self._state.channels[channel].users()
419. ovs = []
420. os = []
421. vs = []
422. plains = []
423. for user in users:
424. numeric = base64.createNumeric(user)
425. if "o" in users[user] and "v" in users[user]:
426. ovs.append(numeric)
427. elif "o" in users[user]:
428. os.append(numeric)
429. elif "v" in users[user]:
430. vs.append(numeric)
431. else:
432. plains.append(numeric)
433.
434. bans = self._state.channels[channel].bans
435.
436. done = False
437.
438. while not done:
439. # Limit to 510 in size
440. remaining = 510 - 6 # origin and token + spacing
441. for arg in burst:
442. remaining -= len(arg)
443. remaining -= 1 # space
444.
445. userstr = ''
446.
447. if len(plains) > 0:
448. while len(plains) and remaining > 6:
449. plain = plains.pop()
450. userstr += plain + ","
451. remaining -= len(plain) + 1
452.
453. if len(vs) > 0:
454. first = True
455. while len(vs) and remaining > 8:
456. v = vs.pop()
457. if first:
458. userstr += v + ":v,"
459. first = False
460. else:
461. userstr += v + ","
462. remaining -= len(v) + 1
463.
464. if len(os) > 0:
465. first = True
466. while len(os) and remaining > 8:
467. o = os.pop()
468. if first:
469. userstr += o + ":o,"
470. first = False
471. else:
472. userstr += o + ","
473. remaining -= len(o) + 1
474.
475. if len(ovs) > 0:
476. first = True
477. while len(ovs) and remaining > 9:
478. ov = ovs.pop()
479. if first:
480. userstr += ov + ":ov,"
481. first = False
482. else:
483. userstr += ov + ","
484. remaining -= len(ov) + 1
485.
486. if userstr != '':
487. burst.append(userstr[:-1])
488.
489. # Bans
490.
491. banstr = ''
492.
493. if len(bans) > 0:
494. first = True
495. while len(bans) and remaining > len(bans[-1]) + 1:
496. ban = bans.pop()
497. if first:
498. banstr += "%" + ban
499. first = False
500. else:
501. banstr += " " + ban
502. remaining -= len(ban) + 1
503.
504. if banstr != '':
505. burst.append(banstr)
506.
507. self._sendLine((self._state.getServerID(), None), "B", burst)
508. burst = [channel, str(self._state.channels[channel].ts)]
509.
510. # Check we're done
511. if len(plains) == 0 and len(vs) == 0 and len(os) == 0 and len(ovs) == 0 and len(bans) == 0:
512. done = True
513.
514. self._sendLine((self._state.getServerID(), None), "EB", [])
515.
516. def writable(self):
517. return (len(self._buffer) > 0)
518.
519. def handle_write(self):
520. sent = self.send(self._buffer)
521. print "SENT: " + self._buffer[:sent]
522. self._buffer = self._buffer[sent:]
523.
524. def handle_close(self):
525. if self.connstate != self.COMPLETE:
526. self._state.quitServer((self._state.getServerID(), None), (self.numeric, None), "Connection closed unexpectedly", self._state.ts())
527. self.connstate = self.COMPLETE
528. self._teardownCallbacks()
529. self.close()
530.
531. def handle_read(self):
532. # Get this chunk
533. self._data += self.recv(512)
534.
535. # Get an entire line
536. nlb = self._data.find("\n")
537. while nlb > -1:
538. line = self._data[:nlb+1]
539. print "HANDLING: " + line
540. # Update state
541. if self.connstate == self.CHALLENGED and self._upstream_password != None:
542. # Check password
543. if self._password == self._upstream_password:
544. self.connstate = self.HANDSHAKE
545. self._parser.registerHandler("SERVER", commands.server.server(self._state, self))
546. else:
547. self.error("Password not as expected")
548. if self.connstate == self.HANDSHAKE and self.numeric != None:
549. self.connstate = self.AUTHENTICATED
550. self._setupParser()
551. # We're all good, send netburst
552. self._sendBurst()
553. if self.connstate < self.AUTHENTICATED:
554. try:
555. self._parser.parsePreAuth(line, (self._state.getServerID(), None))
556. except Exception, e:
557. self.error(str(e))
558. else:
559. try:
560. self._parser.parse(line)
561. except Exception, e:
562. self.error(str(e))
563. # Get our next complete line if one exists
564. self._data = self._data[nlb+1:]
565. nlb = self._data.find("\n")
566. self.do_ping()
567.
568. def _buildModeString(self, modes):
569. modestr = ""
570. curmode = ""
571. modeargs = []
572. for mode in modes:
573. if curmode != mode[0][0]:
574. modestr += mode[0]
575. curmode = mode[0][0]
576. else:
577. modestr += mode[0][1]
578. if mode[1] != None:
579. modeargs.append(str(mode[1]))
580. return (modestr, modeargs)
581.
582. def callbackNewUser(self, (origin, numeric, nickname, username, hostname, modes, ip, hops, ts, fullname)):
583. # Broadcast to all away from origin
584. if self._state.getNextHop(origin) != self.numeric:
585. line = [nickname, str(hops + 1), str(ts), username, hostname]
586. (modestr, modeargs) = self._buildModeString(modes)
587. if modestr != "":
588. line.append(modestr)
589. line += modeargs
590. line.append(base64.toBase64(ip, 6))
591. line.append(base64.createNumeric(numeric))
592. line.append(fullname)
593. self._sendLine(origin, "N", line)
594.
595. def callbackChangeNick(self, (origin, numeric, newnick, newts)):
596. # Broadcast to all away from origin
597. if self._state.getNextHop(origin) != self.numeric:
598. if origin != numeric:
599. self._sendLine(origin, "SN", [base64.createNumeric(numeric), newnick])
600. else:
601. self._sendLine(numeric, "N", [newnick, str(newts)])
602.
603. def callbackNewServer(self, (origin, numeric, name, maxclient, boot_ts, link_ts, protocol, hops, flags, description)):
604. # Broadcast to all away from origin
605. if self._state.getNextHop(origin) != self.numeric:
606. (modestr, modeargs) = self._buildModeString(flags)
607. if modestr == '':
608. modestr = '+'
609. self._sendLine(origin, "S", [name, str(hops + 1), str(boot_ts), str(link_ts), protocol, base64.createNumeric((numeric, maxclient)), modestr, description])
610.
611. def callbackSquit(self, (origin, numeric, reason, ts)):
612. # If this uplink is the one being disconnected
613. if numeric[0] == self.numeric:
614. self.close_connection()
615. self._sendLine(origin, "SQ", [self._state.getServerName(), "0", reason])
616. # Otherwise, broadcast away from origin
617. elif self._state.getNextHop(origin) != self.numeric:
618. self._sendLine(origin, "SQ", [self._state.numeric2nick(numeric), str(ts), reason])
619.
620. def callbackAuthenticate(self, (origin, numeric, acname)):
621. # Broadcast to all away from origin
622. if self._state.getNextHop(origin) != self.numeric:
623. self._sendLine(origin, "AC", [base64.createNumeric(numeric), acname])
624.
625. def callbackAway(self, (numeric, reason)):
626. # Broadcast to all away from origin
627. if self._state.getNextHop(numeric) != self.numeric:
628. self._sendLine(numeric, "A", [reason])
629.
630. def callbackBack(self, (numeric)):
631. # Broadcast to all away from origin
632. if self._state.getNextHop(numeric) != self.numeric:
633. self._sendLine(numeric, "A", [])
634.
635. def callbackChannelCreate(self, (origin, name, ts)):
636. # Broadcast to all servers away from origin
637. if self._state.getNextHop(origin) != self.numeric:
638. self._sendLine(origin, "C", [name, str(ts)])
639.
640. def callbackChannelJoin(self, (origin, numeric, name, modes, ts)):
641. # Broadcast to all servers away from origin
642. if self._state.getNextHop(origin) != self.numeric:
643. # If it's a forced join, must be a SJ
644. if origin != numeric:
645. self._sendLine(origin, "SJ", [base64.createNumeric(numeric), name])
646. else:
647. self._sendLine(origin, "J", [name, str(ts)])
648. # In theory, joins should never be called if the channel already exists
649. # so we must force any modes on
650. if "o" in modes:
651. self.callbackChannelOp((origin, name, numeric))
652. if "v" in modes:
653. self.callbackChannelVoice((origin, name, numeric))
654.
655. def callbackChannelPart(self, (numeric, name, reason)):
656. if self._state.getNextHop(numeric) != self.numeric:
657. self._sendLine(numeric, "P", [name, reason])
658.
659. def callbackPartAll(self, (numeric)):
660. if self._state.getNextHop(numeric) != self.numeric:
661. self._sendLine(numeric, "J", ["0"])
662.
663. def callbackChannelChangeMode(self, (origin, name, modes)):
664. if self._state.getNextHop(origin) != self.numeric:
665. line = [name]
666. (modestr, modeargs) = self._buildModeString(modes)
667. line.append(modestr)
668. line += modeargs
669. line.append(str(self._state.channels[name].ts))
670. self._sendLine(origin, "M", line)
671.
672. def callbackChannelAddBan(self, (origin, name, mask)):
673. self.callbackChannelChangeMode((origin, name, [("+b", mask)]))
674.
675. def callbackChannelRemoveBan(self, (origin, name, ban)):
676. self.callbackChannelChangeMode((origin, name, [("-b", ban)]))
677.
678. def callbackChannelClearBans(self, (origin, name)):
679. if self._state.getNextHop(origin) != self.numeric:
680. self._sendLine(origin, "CM", [name, "b"])
681.
682. def callbackChannelOp(self, (origin, channel, user)):
683. self.callbackChannelChangeMode((origin, channel, [("+o", base64.createNumeric(user))]))
684.
685. def callbackChannelDeop(self, (origin, channel, user)):
686. self.callbackChannelChangeMode((origin, channel, [("-o", base64.createNumeric(user))]))
687.
688. def callbackChannelClearOps(self, (origin, name)):
689. if self._state.getNextHop(origin) != self.numeric:
690. self._sendLine(origin, "CM", [name, "o"])
691.
692. def callbackChannelVoice(self, (origin, channel, user)):
693. self.callbackChannelChangeMode((origin, channel, [("+v", base64.createNumeric(user))]))
694.
695. def callbackChannelDevoice(self, (origin, channel, user)):
696. self.callbackChannelChangeMode((origin, channel, [("-v", base64.createNumeric(user))]))
697.
698. def callbackChannelClearVoices(self, (origin, name)):
699. if self._state.getNextHop(origin) != self.numeric:
700. self._sendLine(origin, "CM", [name, "v"])
701.
702. def _getGline(self, mask):
703. for gline in self._state.glines():
704. if mask == gline[0]:
705. return gline
706.
707. def callbackGlineAdd(self, (origin, mask, target, expires, description)):
708. gline = self._getGline(mask)
709. if self._state.getNextHop(origin) != self.numeric and target == None:
710. self._sendLine(origin, "GL", ["*", "+" + mask, str(expires - gline[4]), str(gline[4]), description])
711. elif self._state.getNextHop((target, None)) == self.numeric:
712. self._sendLine(origin, "GL", [base64.createNumeric((target, None)), "+" + mask, str(expires - gline[4]), str(gline[4]), description])
713.
714. def callbackGlineRemove(self, (origin, mask, target)):
715. gline = self._getGline(mask)
716. if self._state.getNextHop(origin) != self.numeric and target == None:
717. self._sendLine(origin, "GL", ["*", "-" + mask, str(gline[2] - gline[4]), str(gline[4]), gline[1]])
718. elif self._state.getNextHop((target, None)) == self.numeric:
719. self._sendLine(origin, "GL", [base64.createNumeric((target, None)), "-" + mask, str(gline[2] - gline[4]), str(gline[4]), gline[1]])
720.
721. def callbackInvite(self, (origin, target, channel)):
722. if self._state.getNextHop(target) == self.numeric:
723. self._sendLine(origin, "I", [self._state.numeric2nick(target), channel])
724.
725. def _getJupe(self, server):
726. for jupe in self._state.jupes():
727. if server == jupe[0]:
728. return jupe
729.
730. def callbackJupeAdd(self, (origin, server, target, expire, reason)):
731. jupe = self._getJupe(server)
732. if self._state.getNextHop(origin) != self.numeric and target == None:
733. self._sendLine(origin, "JU", ["*", "+" + server, str(expire - jupe[4]), str(jupe[4]), reason])
734. elif self._state.getNextHop((target, None)) == self.numeric:
735. self._sendLine(origin, "JU", [base64.createNumeric((target, None)), "+" + server, str(expire - jupe[4]), str(jupe[4]), reason])
736.
737. def callbackJupeRemove(self, (origin, server, target)):
738. jupe = self._getJupe(server)
739. if self._state.getNextHop(origin) != self.numeric and target == None:
740. self._sendLine(origin, "JU", ["*", "-" + server, str(jupe[2] - jupe[4]), str(jupe[4]), jupe[1]])
741. elif self._state.getNextHop((target, None)) == self.numeric:
742. self._sendLine(origin, "JU", [base64.createNumeric((target, None)), "-" + server, str(jupe[2] - jupe[4]), str(jupe[4]), jupe[1]])
743.
744. def callbackAdminInfo(self, (origin, target)):
745. if self._state.getNextHop(target) == self.numeric:
746. self._sendLine(origin, "AD", [base64.createNumeric(target)])
747.
748. def callbackInfoRequest(self, (origin, target)):
749. if self._state.getNextHop(target) == self.numeric:
750. self._sendLine(origin, "F", [base64.createNumeric(target)])
751.
752. def callbackKick(self, (origin, channel, target, reason)):
753. if self._state.getNextHop(origin) != self.numeric:
754. self._sendLine(origin, "K", [channel, base64.createNumeric(target), reason])
755.
756. def callbackZombiePart(self, (origin, channel)):
757. self.callbackChannelPart((origin, channel, "Zombie parting channel"))
758.
759. def callbackChannelDestroy(self, (origin, channel, ts)):
760. if self._state.getNextHop(origin) != self.numeric:
761. self._sendLine(origin, "DE", [channel, str(ts)])
762.
763. def callbackQuit(self, (numeric, reason, causedbysquit)):
764. if not causedbysquit and self._state.getNextHop(numeric) != self.numeric:
765. self._sendLine(numeric, "Q", [reason])
766.
767. def callbackKill(self, (origin, target, path, reason)):
768. if self._state.getNextHop(target) == self.numeric:
769. self._sendLine(origin, "D", [base64.createNumeric(target), "!".join(path) + " (" + reason + ")"])
770.
771. def callbackLusers(self, (origin, target, dummy)):
772. if self._state.getNextHop(target) == self.numeric:
773. self._sendLine(origin, "LU", [dummy, base64.createNumeric(target)])
774.
775. def callbackLinks(self, (origin, target, mask)):
776. if self._state.getNextHop(target) == self.numeric:
777. self._sendLine(origin, "LI", [base64.createNumeric(target), mask])
778.
779. def callbackChangeUserMode(self, (numeric, modes)):
780. if self._state.getNextHop(numeric) != self.numeric:
781. line = [self._state.numeric2nick(numeric)]
782. (modestr, modeargs) = self._buildModeString(modes)
783. line.append(modestr)
784. line += modeargs
785. self._sendLine(numeric, "M", line)
786.
787. def callbackMOTD(self, (numeric, target)):
788. if self._state.getNextHop(target) == self.numeric:
789. self._sendLine(numeric, "MO", [base64.createNumeric(target)])
790.
791. def callbackNames(self, (origin, target, channels)):
792. if self._state.getNextHop(target) == self.numeric:
793. self._sendLine(origin, "E", [",".join(channels), base64.createNumeric(target)])
794.
795. def callbackTopic(self, (origin, channel, topic, topic_ts, channel_ts)):
796. if self._state.getNextHop(origin) != self.numeric:
797. self._sendLine(origin, "T", [channel, str(channel_ts), str(topic_ts), topic])
798.
799. def callbackSilenceAdd(self, (numeric, mask)):
800. if self._state.getNextHop(numeric) != self.numeric:
801. self._sendLine(numeric, "U", ["*", mask])
802.
803. def callbackSilenceRemove(self, (numeric, mask)):
804. if self._state.getNextHop(numeric) != self.numeric:
805. self._sendLine(numeric, "U", ["*", "-" + mask])
806.
807. def callbackRequestVersion(self, (origin, target)):
808. if self._state.getNextHop(target) == self.numeric:
809. self._sendLine(origin, "V", [base64.createNumeric(target)])
810.
811. def callbackRequestStats(self, (origin, target, stat, arg)):
812. if self._state.getNextHop(target) == self.numeric:
813. if arg != None:
814. self._sendLine(origin, "R", [stat, base64.createNumeric(target), arg])
815. else:
816. self._sendLine(origin, "R", [stat, base64.createNumeric(target)])
817.
818. def callbackTrace(self, (origin, search, target)):
819. if self._state.getNextHop(target) == self.numeric:
820. self._sendLine(origin, "TR", [search, base64.createNumeric(target)])
821.
822. def callbackPing(self, (origin, source, target)):
823. if target[0] == self._state.getServerID() and self._state.getNextHop(origin) == self.numeric:
824. self._sendLine((self._state.getServerID(), None), "Z", [base64.createNumeric((self._state.getServerID(), None)), source])
825. elif self._state.getNextHop(target) == self.numeric:
826. self._sendLine(origin, "G", [source, base64.createNumeric(target)])
827.
828. def callbackPong(self, (origin, source, target)):
829. if self._state.getNextHop(target) == self.numeric:
830. self._sendLine(origin, "Z", [base64.createNumeric(source), base64.createNumeric(target)])
831.
832. def callbackRequestWhois(self, (origin, target, search)):
833. if self._state.getNextHop(target) == self.numeric:
834. self._sendLine(origin, "W", [base64.createNumeric(target), search])
835.
836. def _multiTargetMessage(self, origin, target, type, message):
837. if self._state.getNextHop(target) == self.numeric:
838. self._sendLine(origin, type, [base64.createNumeric(target), message])
839. elif target[0] == "#":
840. if self._state.getNextHop(origin) != self.numeric:
841. for user in self._state.channels[target].users():
842. if self._state.getNextHop(user) == self.numeric:
843. self._sendLine(origin, type, [target, message])
844. elif "@" in target:
845. target_parts = target.split("@")
846. if self._state.getNextHop(self._state.nick2numeric(target_parts[1])) == self.numeric:
847. self._sendLine(origin, type, [target, message])
848. elif "$" in target:
849. mask = target[1:]
850. for server in self._state.servers:
851. if self._state.getNextHop((server, None)) == self.numeric and fnmatch.fnmatch(self._state.servers[server].name, mask):
852. self._sendLine(origin, type, [target, message])
853. return
854.
855. def callbackPrivmsg(self, (origin, target, message)):
856. self._multiTargetMessage(origin, target, "P", message)
857.
858. def callbackNotice(self, (origin, target, message)):
859. self._multiTargetMessage(origin, target, "O", message)
860.
861. def callbackOobmsg(self, (origin, target, type, args)):
862. if self._state.getNextHop(target) == self.numeric:
863. self._sendLine(origin, type, [base64.createNumeric(target)] + args)
864.
865. def callbackWallops(self, (origin, message)):
866. if self._state.getNextHop(origin) != self.numeric:
867. self._sendLine(origin, "WA", [message])
868.
869. def callbackWallusers(self, (origin, message)):
870. if self._state.getNextHop(origin) != self.numeric:
871. self._sendLine(origin, "WU", [message])
872.
873. def callbackWallvoices(self, (origin, channel, message)):
874. if self._state.getNextHop(origin) != self.numeric:
875. for user in self._state.channels[channel].users():
876. if self._state.getNextHop(user) == self.numeric and (self._state.channels[channel].isvoice(user) or self._state.channels[channel].isop(user)):
877. self._sendLine(origin, "WV", [channel, message])
878. return
879.
880. def callbackWallchops(self, (origin, channel, message)):
881. if self._state.getNextHop(origin) != self.numeric:
882. for user in self._state.channels[channel].users():
883. if self._state.getNextHop(user) == self.numeric and self._state.channels[channel].isop(user):
884. self._sendLine(origin, "WC", [channel, message])
885. return
886.
887.
888. class ConnectionError(Exception):
889. """ When an error occurs in a connection """
890. pass