Merge lp:~stefanor/ibid/summon-330869 into lp:~ibid-core/ibid/old-trunk-1.6

Proposed by Stefano Rivera
Status: Merged
Approved by: Michael Gorven
Approved revision: 796
Merged at revision: 817
Proposed branch: lp:~stefanor/ibid/summon-330869
Merge into: lp:~ibid-core/ibid/old-trunk-1.6
Diff against target: 894 lines (+349/-106)
14 files modified
ibid/__init__.py (+2/-0)
ibid/plugins/__init__.py (+1/-1)
ibid/plugins/core.py (+32/-4)
ibid/plugins/games.py (+4/-4)
ibid/plugins/identity.py (+77/-3)
ibid/plugins/irc.py (+3/-3)
ibid/plugins/log.py (+48/-36)
ibid/plugins/memo.py (+1/-1)
ibid/plugins/seen.py (+7/-6)
ibid/source/campfire.py (+3/-3)
ibid/source/dc.py (+15/-1)
ibid/source/irc.py (+82/-15)
ibid/source/jabber.py (+47/-26)
ibid/source/silc.py (+27/-3)
To merge this branch: bzr merge lp:~stefanor/ibid/summon-330869
Reviewer Review Type Date Requested Status
Michael Gorven Approve
Jonathan Hitchcock Approve
Review via email: mp+16616@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Stefano Rivera (stefanor) wrote :

OK I can't reproduce the problem that was holding back this proposal.

lp:~stefanor/ibid/summon-330869 updated
794. By Stefano Rivera

We now have ibid.compat

795. By Stefano Rivera

Werewolf missed the event_types unicoding

Revision history for this message
Jonathan Hitchcock (vhata) wrote :

Seeeems good.

review: Approve
lp:~stefanor/ibid/summon-330869 updated
796. By Stefano Rivera

Merge from trunk

Revision history for this message
Michael Gorven (mgorven) wrote :

Seems fine.
 review approve
 status approved

review: Approve
lp:~stefanor/ibid/summon-330869 updated
797. By Stefano Rivera

Merge from trunk

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ibid/__init__.py'
2--- ibid/__init__.py 2009-10-16 16:31:34 +0000
3+++ ibid/__init__.py 2009-12-30 22:21:13 +0000
4@@ -10,6 +10,7 @@
5 import twisted.python.log
6
7 import ibid.core
8+from ibid.compat import defaultdict
9 from ibid.config import FileConfig
10
11 class InsensitiveDict(dict):
12@@ -32,6 +33,7 @@
13 service = None
14 options = {}
15 rpc = {}
16+channels = defaultdict(lambda: defaultdict(set))
17
18 def twisted_log(eventDict):
19 log = logging.getLogger('twisted')
20
21=== modified file 'ibid/plugins/__init__.py'
22--- ibid/plugins/__init__.py 2009-12-10 09:56:44 +0000
23+++ ibid/plugins/__init__.py 2009-12-30 22:21:13 +0000
24@@ -26,7 +26,7 @@
25 explicitly required in the configuration file
26 """
27
28- event_types = ('message',)
29+ event_types = (u'message',)
30 addressed = True
31 processed = False
32 priority = 0
33
34=== modified file 'ibid/plugins/core.py'
35--- ibid/plugins/core.py 2009-12-30 20:53:06 +0000
36+++ ibid/plugins/core.py 2009-12-30 22:21:13 +0000
37@@ -7,6 +7,7 @@
38 from ibid.compat import any
39 from ibid.config import IntOption, ListOption, DictOption
40 from ibid.plugins import Processor, handler
41+from ibid.plugins.identity import identify
42
43 class Addressed(Processor):
44
45@@ -43,7 +44,7 @@
46
47 priority = -1600
48 addressed = False
49- event_types = ('message', 'action', 'notice')
50+ event_types = (u'message', u'action', u'notice')
51
52 pattern = re.compile(r'^\s*(.*?)\s*[?!.]*\s*$', re.DOTALL)
53
54@@ -58,7 +59,7 @@
55
56 priority = -1500
57 addressed = False
58- event_types = ('message', 'action', 'notice')
59+ event_types = (u'message', u'action', u'notice')
60
61 nicks = ListOption('ignore', 'List of nicks to ignore', [])
62
63@@ -85,7 +86,6 @@
64 priority = 1600
65 processed = True
66 addressed = False
67-
68 event_types = ('message', 'action', 'notice', 'state')
69
70 acknowledgements = ListOption('acknowledgements', 'Responses for positive acknowledgements',
71@@ -148,7 +148,7 @@
72 class RateLimit(Processor):
73
74 priority = -1000
75- event_types = ('message', 'action', 'notice')
76+ event_types = (u'message', u'action', u'notice')
77
78 limit_time = IntOption('limit_time', 'Time period over which to measure messages', 10)
79 limit_messages = IntOption('limit_messages', 'Number of messages to allow during the time period', 5)
80@@ -210,4 +210,32 @@
81 elif isinstance(object, str):
82 self.log.warning(u'Found a non-unicode string: %s' % object)
83
84+class ChannelTracker(Processor):
85+ priority = -1550
86+ addressed = False
87+ event_types = (u'state', u'source')
88+
89+ @handler
90+ def track(self, event):
91+ if event.type == u'source':
92+ if event.status == u'disconnected':
93+ ibid.channels.pop(event.source, None)
94+ elif event.status == u'left':
95+ ibid.channels[event.source].pop(event.channel, None)
96+ elif event.public:
97+ if event.state == u'online' and hasattr(event, 'othername'):
98+ oldid = identify(event.session, event.source, event.othername)
99+ for channel in ibid.channels[event.source].values():
100+ if oldid in channel:
101+ channel.remove(oldid)
102+ channel.add(event.identity)
103+ elif event.state == u'online':
104+ ibid.channels[event.source][event.channel].add(event.identity)
105+ elif event.state == u'offline' and not hasattr(event, 'othername'):
106+ if event.channel:
107+ ibid.channels[event.source][event.channel].remove(event.identity)
108+ else:
109+ for channel in ibid.channels[event.source].values():
110+ channel.discard(event.identity)
111+
112 # vi: set et sta sw=4 ts=4:
113
114=== modified file 'ibid/plugins/games.py'
115--- ibid/plugins/games.py 2009-12-30 14:08:03 +0000
116+++ ibid/plugins/games.py 2009-12-30 22:21:13 +0000
117@@ -218,7 +218,7 @@
118 feature = 'duel'
119
120 # Parameters for Processor:
121- event_types = ('message', 'action')
122+ event_types = (u'message', u'action')
123
124 addressed = BoolOption('addressed', 'Must the bot be addressed?', True)
125
126@@ -400,7 +400,7 @@
127 class DuelFlee(Processor):
128 feature = 'duel'
129 addressed = False
130- event_types = ('state',)
131+ event_types = (u'state',)
132
133 @handler
134 def dueller_fled(self, event):
135@@ -470,7 +470,7 @@
136 seer_delay = IntOption('seer_delay',
137 'Number of players between extra wolf and extra seer', 4)
138
139- event_types = ('message', 'action')
140+ event_types = (u'message', u'action')
141
142 @match(r'^(?:start|play|begin)s?\b.*werewolf$')
143 def prestart(self, event):
144@@ -843,7 +843,7 @@
145
146 class WerewolfState(Processor):
147 feature = 'werewolf'
148- event_types = ('state',)
149+ event_types = (u'state',)
150
151 @handler
152 def state_change(self, event):
153
154=== modified file 'ibid/plugins/identity.py'
155--- ibid/plugins/identity.py 2009-12-22 14:49:33 +0000
156+++ ibid/plugins/identity.py 2009-12-30 22:21:13 +0000
157@@ -3,9 +3,10 @@
158 import logging
159
160 import ibid
161-from ibid.db import eagerload, IntegrityError
162+from ibid.config import Option
163+from ibid.db import eagerload, IntegrityError, and_, or_
164 from ibid.db.models import Account, Identity, Attribute
165-from ibid.plugins import Processor, match, auth_responses
166+from ibid.plugins import Processor, match, handler, auth_responses, authorise
167 from ibid.utils import human_join
168
169 help = {}
170@@ -368,11 +369,79 @@
171 'identities': human_join(u'%s on %s' % (identity.identity, identity.source) for identity in account.identities),
172 })
173
174+help['summon'] = u"Get the attention of a person via different source"
175+class Summon(Processor):
176+ u"summon <person> [via <source>]"
177+ feature = 'summon'
178+ permission = u'summon'
179+
180+ default_source = Option('default_source',
181+ u'Default source to summon people via', u'jabber')
182+
183+ @authorise(fallthrough=False)
184+ @match(r'^summon\s+(\S+)(?:\s+(?:via|on|using)\s+(\S+))?$')
185+ def summon(self, event, who, source):
186+ if not source:
187+ source = self.default_source
188+
189+ if source.lower() not in ibid.sources:
190+ event.addresponse(u"I'm afraid that I'm not connected to %s",
191+ source)
192+ return
193+
194+ account = event.session.query(Account) \
195+ .options(eagerload('identities')) \
196+ .join(Identity) \
197+ .filter(
198+ or_(
199+ and_(
200+ Identity.identity == who,
201+ Identity.source == event.source,
202+ ),
203+ Account.username == who,
204+ )) \
205+ .first()
206+
207+ if account:
208+ for other_identity in [id for id
209+ in account.identities
210+ if id.source.lower() == source.lower()]:
211+ if any(True for channel
212+ in ibid.channels[other_identity.source].itervalues()
213+ if other_identity.id in channel):
214+ event.addresponse(u'Your presence has been requested by '
215+ u'%(who)s in %(channel)s on %(source)s.',
216+ {
217+ 'who': event.sender['nick'],
218+ 'channel': (not event.public)
219+ and u'private' or event.channel,
220+ 'source': event.source,
221+ }, target=other_identity.identity,
222+ source=other_identity.source, address=False)
223+ event.addresponse(True)
224+ else:
225+ event.addresponse(
226+ u"Sorry %s doesn't appear to be available right now.",
227+ who)
228+ return
229+
230+ event.addresponse(
231+ u"Sorry, I don't know how to find %(who)s on %(source)s. "
232+ u'%(who)s must first link an identity on %(source)s.', {
233+ 'who': who,
234+ 'source': source,
235+ })
236+ return
237+
238 class Identify(Processor):
239
240 priority = -1600
241+ addressed = False
242+ processed = True
243+ event_types = (u'message', u'state', u'action', u'notice')
244
245- def process(self, event):
246+ @handler
247+ def handle(self, event):
248 if event.sender:
249 if (event.source, event.sender['connection']) in identify_cache:
250 (event.identity, event.account) = identify_cache[(event.source, event.sender['connection'])]
251@@ -414,4 +483,9 @@
252 else:
253 return (event.identity,)
254
255+def identify(session, source, id):
256+ identity = session.query(Identity) \
257+ .filter_by(source=source, identity=id).first()
258+ return identity and identity.id
259+
260 # vi: set et sta sw=4 ts=4:
261
262=== modified file 'ibid/plugins/irc.py'
263--- ibid/plugins/irc.py 2009-10-20 15:45:46 +0000
264+++ ibid/plugins/irc.py 2009-12-30 22:21:13 +0000
265@@ -43,8 +43,8 @@
266 source.join(channel)
267 event.addresponse(u'Joining %s', channel)
268 else:
269- source.part(channel)
270- event.addresponse(u'Parting %s', channel)
271+ source.leave(channel)
272+ event.addresponse(u'Leaving %s', channel)
273
274 @match(r'^change\s+nick\s+to\s+(\S+)(?:\s+on\s+(\S+))?$')
275 @authorise()
276@@ -66,7 +66,7 @@
277 event.addresponse(u'Changing nick to %s', nick)
278
279 class NickServ(Processor):
280- event_types = ('notice',)
281+ event_types = (u'notice',)
282
283 def is_nickserv(self, event):
284 source_cfg = ibid.config['sources'][event.source]
285
286=== modified file 'ibid/plugins/log.py'
287--- ibid/plugins/log.py 2009-12-14 13:40:46 +0000
288+++ ibid/plugins/log.py 2009-12-30 22:21:13 +0000
289@@ -7,7 +7,7 @@
290 from dateutil.tz import tzlocal, tzutc
291
292 import ibid
293-from ibid.plugins import Processor
294+from ibid.plugins import Processor, handler
295 from ibid.config import Option, BoolOption
296 from ibid.event import Event
297
298@@ -15,6 +15,7 @@
299
300 addressed = False
301 processed = True
302+ event_types = (u'message', u'state', u'action', u'notice')
303 priority = 1900
304
305 log = Option('log', 'Log file to log messages to. Can contain substitutions: source, channel, year, month, day',
306@@ -31,6 +32,8 @@
307 u'%(timestamp)s -%(sender_nick)s- %(message)s')
308 presence_format = Option('presence_format', 'Format string for presence events',
309 u'%(timestamp)s %(sender_nick)s (%(sender_connection)s) is now %(state)s')
310+ rename_format = Option('rename_format', 'Format string for rename events',
311+ u'%(timestamp)s %(sender_nick)s (%(sender_connection)s) has renamed to %(new_nick)s')
312
313 public_mode = Option('public_mode',
314 u'File Permissions mode for public channels, in octal', '644')
315@@ -72,42 +75,51 @@
316 return self.logs[filename]
317
318 def log_event(self, event):
319- if event.type in ('message', 'state', 'action', 'notice'):
320- when = event.time
321- if not self.date_utc:
322- when = when.replace(tzinfo=tzutc()).astimezone(tzlocal())
323-
324- format = {
325- 'message': self.message_format,
326- 'state': self.presence_format,
327- 'action': self.action_format,
328- 'notice': self.notice_format,
329- }[event.type]
330-
331- fields = {
332- 'source': event.source,
333- 'channel': event.channel,
334- 'sender_connection': event.sender['connection'],
335- 'sender_id': event.sender['id'],
336- 'sender_nick': event.sender['nick'],
337- 'timestamp': unicode(
338- when.strftime(self.timestamp_format.encode('utf8')),
339- 'utf8'),
340- }
341-
342- if event.type == 'state':
343+ when = event.time
344+ if not self.date_utc:
345+ when = when.replace(tzinfo=tzutc()).astimezone(tzlocal())
346+
347+ format = {
348+ 'message': self.message_format,
349+ 'state': self.presence_format,
350+ 'action': self.action_format,
351+ 'notice': self.notice_format,
352+ }[event.type]
353+
354+ # We get two events on a rename, ignore one of them
355+ if event.type == 'state' and hasattr(event, 'othername'):
356+ if event.state == 'online':
357+ return
358+ format = self.rename_format
359+
360+ fields = {
361+ 'source': event.source,
362+ 'channel': event.channel,
363+ 'sender_connection': event.sender['connection'],
364+ 'sender_id': event.sender['id'],
365+ 'sender_nick': event.sender['nick'],
366+ 'timestamp': unicode(
367+ when.strftime(self.timestamp_format.encode('utf8')),
368+ 'utf8')
369+ }
370+
371+ if event.type == 'state':
372+ if hasattr(event, 'othername'):
373+ fields['new_nick'] = event.othername
374+ else:
375 fields['state'] = event.state
376- elif isinstance(event.message, dict):
377- fields['message'] = event.message['raw']
378- else:
379- fields['message'] = event.message
380-
381- file = self.get_logfile(event)
382-
383- file.write((format % fields).encode('utf-8') + '\n')
384- file.flush()
385-
386- def process(self, event):
387+ elif isinstance(event.message, dict):
388+ fields['message'] = event.message['raw']
389+ else:
390+ fields['message'] = event.message
391+
392+ file = self.get_logfile(event)
393+
394+ file.write((format % fields).encode('utf-8') + '\n')
395+ file.flush()
396+
397+ @handler
398+ def log_handler(self, event):
399 self.log_event(event)
400
401 for response in event.responses:
402
403=== modified file 'ibid/plugins/memo.py'
404--- ibid/plugins/memo.py 2009-12-20 21:15:42 +0000
405+++ ibid/plugins/memo.py 2009-12-30 22:21:13 +0000
406@@ -285,7 +285,7 @@
407 class Notify(Processor):
408 feature = 'memo'
409
410- event_types = ('state',)
411+ event_types = (u'state',)
412 addressed = False
413 processed = True
414
415
416=== modified file 'ibid/plugins/seen.py'
417--- ibid/plugins/seen.py 2009-12-20 21:15:42 +0000
418+++ ibid/plugins/seen.py 2009-12-30 22:21:13 +0000
419@@ -5,7 +5,7 @@
420 Table, Column, ForeignKey, UniqueConstraint, \
421 relation, IntegrityError, Base, VersionedSchema
422 from ibid.db.models import Identity, Account
423-from ibid.plugins import Processor, match
424+from ibid.plugins import Processor, match, handler
425 from ibid.utils import ago, format_date
426
427 log = logging.getLogger('plugins.seen')
428@@ -60,11 +60,12 @@
429 feature = 'seen'
430
431 priority = 1500
432-
433- def process(self, event):
434- if event.type != 'message' and event.type != 'state':
435- return
436-
437+ event_types = (u'message', u'state')
438+ addressed = False
439+ processed = True
440+
441+ @handler
442+ def see(self, event):
443 sighting = event.session.query(Sighting) \
444 .filter_by(identity_id=event.identity, type=event.type).first()
445 if not sighting:
446
447=== modified file 'ibid/source/campfire.py'
448--- ibid/source/campfire.py 2009-12-30 16:29:10 +0000
449+++ ibid/source/campfire.py 2009-12-30 22:21:13 +0000
450@@ -84,7 +84,7 @@
451 def join(self, room_name):
452 return self.join_room(self._locate_room(room_name))
453
454- def part(self, room_name):
455+ def leave(self, room_name):
456 return self.leave_room(self._locate_room(room_name))
457
458 class SourceFactory(IbidSourceFactory):
459@@ -122,7 +122,7 @@
460 def join(self, room_name):
461 return self.client.join(room_name)
462
463- def part(self, room_name):
464- return self.client.part(room_name)
465+ def leave(self, room_name):
466+ return self.client.leave(room_name)
467
468 # vi: set et sta sw=4 ts=4:
469
470=== modified file 'ibid/source/dc.py'
471--- ibid/source/dc.py 2009-12-30 16:29:10 +0000
472+++ ibid/source/dc.py 2009-12-30 22:21:13 +0000
473@@ -42,6 +42,11 @@
474
475 def connectionLost(self, reason):
476 self.factory.log.info(u"Disconnected (%s)", reason)
477+
478+ event = Event(self.factory.name, u'source')
479+ event.status = u'disconnected'
480+ ibid.dispatcher.dispatch(event)
481+
482 dcwords.DCClient.connectionLost(self, reason)
483
484 def signedOn(self):
485@@ -51,6 +56,16 @@
486 names.append(self.my_nickname)
487 ibid.config.plugins['core']['names'] = names
488 ibid.reloader.reload_config()
489+
490+ event = Event(self.factory.name, u'source')
491+ event.status = u'connected'
492+ ibid.dispatcher.dispatch(event)
493+
494+ event = Event(self.factory.name, u'source')
495+ event.channel = u'$public'
496+ event.status = u'joined'
497+ ibid.dispatcher.dispatch(event)
498+
499 self.factory.log.info(u"Signed on")
500
501 def _create_event(self, type, user):
502@@ -60,7 +75,6 @@
503 event.sender['nick'] = user
504 event.channel = u'$public'
505 event.public = True
506- event.source = self.factory.name
507 return event
508
509 def _state_event(self, user, action):
510
511=== modified file 'ibid/source/irc.py'
512--- ibid/source/irc.py 2009-12-30 22:01:38 +0000
513+++ ibid/source/irc.py 2009-12-30 22:21:13 +0000
514@@ -22,15 +22,23 @@
515
516 def connectionMade(self):
517 self.nickname = self.factory.nick.encode('utf-8')
518+
519 irc.IRCClient.connectionMade(self)
520+
521 self.factory.resetDelay()
522 self.factory.proto = self
523 self.auth_callbacks = {}
524+ self.mode_prefixes = '@+'
525 self._ping_deferred = reactor.callLater(self.factory.ping_interval, self._idle_ping)
526 self.factory.log.info(u"Connected")
527
528 def connectionLost(self, reason):
529 self.factory.log.info(u"Disconnected (%s)", reason)
530+
531+ event = Event(self.factory.name, u'source')
532+ event.status = u'disconnected'
533+ ibid.dispatcher.dispatch(event)
534+
535 irc.IRCClient.connectionLost(self, reason)
536
537 def _idle_ping(self):
538@@ -73,27 +81,30 @@
539 self.join(channel.encode('utf-8'))
540 self.factory.log.info(u"Signed on")
541
542+ event = Event(self.factory.name, u'source')
543+ event.status = u'connected'
544+ ibid.dispatcher.dispatch(event)
545+
546 def _create_event(self, type, user, channel):
547 nick = user.split('!', 1)[0]
548 event = Event(self.factory.name, type)
549- event.sender['connection'] = unicode(user, 'utf-8', 'replace')
550- event.sender['id'] = unicode(nick, 'utf-8', 'replace')
551+ event.sender['connection'] = user
552+ event.sender['id'] = nick
553 event.sender['nick'] = event.sender['id']
554- event.channel = unicode(channel, 'utf-8', 'replace')
555+ event.channel = channel
556 event.public = True
557- event.source = self.factory.name
558 return event
559
560- def _state_event(self, user, channel, action, kicker=None, message=None):
561+ def _state_event(self, user, channel, action, kicker=None, message=None, othername=None):
562 event = self._create_event(u'state', user, channel)
563 event.state = action
564 if message:
565- event.message = unicode(message, 'utf-8', 'replace')
566+ event.message = message
567 if kicker:
568- event.kicker = unicode(kicker, 'utf-8', 'replace')
569+ event.kicker = kicker
570 self.factory.log.debug(u"%s has been kicked from %s by %s (%s)", event.sender['id'], event.channel, event.kicker, event.message)
571- else:
572- self.factory.log.debug(u"%s has %s %s", user, action, channel)
573+ elif othername:
574+ event.othername = othername
575 ibid.dispatcher.dispatch(event).addCallback(self.respond)
576
577 def privmsg(self, user, channel, msg):
578@@ -106,6 +117,9 @@
579 self._message_event(u'action', user, channel, msg)
580
581 def _message_event(self, msgtype, user, channel, msg):
582+ user = unicode(user, 'utf-8', 'replace')
583+ channel = unicode(channel, 'utf-8', 'replace')
584+
585 event = self._create_event(msgtype, user, channel)
586 event.message = unicode(msg, 'utf-8', 'replace')
587 self.factory.log.debug(u"Received %s from %s in %s: %s", msgtype, event.sender['id'], event.channel, event.message)
588@@ -120,16 +134,32 @@
589 ibid.dispatcher.dispatch(event).addCallback(self.respond)
590
591 def userJoined(self, user, channel):
592+ user = unicode(user, 'utf-8', 'replace')
593+ channel = unicode(channel, 'utf-8', 'replace')
594 self._state_event(user, channel, u'online')
595
596 def userLeft(self, user, channel):
597+ user = unicode(user, 'utf-8', 'replace')
598+ channel = unicode(channel, 'utf-8', 'replace')
599 self._state_event(user, channel, u'offline')
600
601+ def userRenamed(self, oldname, newname):
602+ oldname = unicode(oldname, 'utf-8', 'replace')
603+ newname = unicode(newname, 'utf-8', 'replace')
604+ self._state_event(oldname, None, u'offline', othername=newname)
605+ self._state_event(newname, None, u'online', othername=oldname)
606+
607 def userQuit(self, user, channel):
608 # Channel contains the quit message
609- self._state_event(user, '', u'offline', message=channel)
610+ user = unicode(user, 'utf-8', 'replace')
611+ channel = unicode(channel, 'utf-8', 'replace')
612+ self._state_event(user, None, u'offline', message=channel)
613
614 def userKicked(self, kickee, channel, kicker, message):
615+ kickee = unicode(kickee, 'utf-8', 'replace')
616+ channel = unicode(channel, 'utf-8', 'replace')
617+ kicker = unicode(kicker, 'utf-8', 'replace')
618+ message = unicode(message, 'utf-8', 'replace')
619 self._state_event(kickee, channel, u'kicked', kicker, message)
620
621 def respond(self, event):
622@@ -149,6 +179,7 @@
623 self.factory.log.debug(u"Set topic in %s to %s", target, message)
624 elif response.get('action', False):
625 # We can't use self.me() because it prepends a # onto channel names
626+ # See http://twistedmatrix.com/trac/ticket/3910
627 self.ctcpMakeQuery(raw_target, [('ACTION', raw_message)])
628 self.factory.log.debug(u"Sent action to %s: %s", target, message)
629 elif response.get('notice', False):
630@@ -162,9 +193,21 @@
631 self.factory.log.info(u"Joining %s", channel)
632 irc.IRCClient.join(self, channel.encode('utf-8'))
633
634- def part(self, channel):
635+ def joined(self, channel):
636+ event = Event(self.factory.name, u'source')
637+ event.channel = channel
638+ event.status = u'joined'
639+ ibid.dispatcher.dispatch(event)
640+
641+ def leave(self, channel):
642 self.factory.log.info(u"Leaving %s", channel)
643- irc.IRCClient.part(self, channel.encode('utf-8'))
644+ irc.IRCClient.leave(self, channel.encode('utf-8'))
645+
646+ def left(self, channel):
647+ event = Event(self.factory.name, u'source')
648+ event.channel = channel
649+ event.status = u'left'
650+ ibid.dispatcher.dispatch(event)
651
652 def authenticate(self, nick, callback):
653 self.sendLine('WHOIS %s' % nick.encode('utf-8'))
654@@ -186,6 +229,28 @@
655 elif command == "RPL_ENDOFWHOIS":
656 self.do_auth_callback(params[1], False)
657
658+ def irc_RPL_BOUNCE(self, prefix, params):
659+ # Broken in IrcClient :/
660+ # See http://twistedmatrix.com/trac/ticket/3285
661+ if params[-1] in ('are available on this server', 'are supported by this server'):
662+ self.isupport(params[1:-1])
663+ else:
664+ self.bounce(params[1])
665+
666+ def isupport(self, options):
667+ "Server supports message"
668+ for option in options:
669+ if option.startswith('PREFIX='):
670+ self.mode_prefixes = option.split(')', 1)[1]
671+
672+ def irc_RPL_NAMREPLY(self, prefix, params):
673+ channel = params[2]
674+ for user in params[3].split():
675+ if user[0] in self.mode_prefixes:
676+ user = user[1:]
677+ if user != self.nickname:
678+ self.userJoined(user, channel)
679+
680 def ctcpQuery_VERSION(self, user, channel, data):
681 nick = user.split("!")[0]
682 self.ctcpMakeReply(nick, [('VERSION', 'Ibid %s' % (ibid_version() or '',))])
683@@ -244,8 +309,8 @@
684 def join(self, channel):
685 return self.proto.join(channel)
686
687- def part(self, channel):
688- return self.proto.part(channel)
689+ def leave(self, channel):
690+ return self.proto.leave(channel)
691
692 def change_nick(self, nick):
693 return self.proto.setNick(nick.encode('utf-8'))
694@@ -254,7 +319,9 @@
695 return self.proto.send(response)
696
697 def logging_name(self, identity):
698- return identity.split('!')[0]
699+ if identity is None:
700+ return u''
701+ return identity.split(u'!')[0]
702
703 def url(self):
704 return u'irc://%s@%s:%s' % (self.nick, self.server, self.port)
705
706=== modified file 'ibid/source/jabber.py'
707--- ibid/source/jabber.py 2009-12-30 16:29:10 +0000
708+++ ibid/source/jabber.py 2009-12-30 22:21:13 +0000
709@@ -1,6 +1,6 @@
710 import logging
711
712-from wokkel import client, xmppim
713+from wokkel import client, xmppim, subprotocols
714 from twisted.internet import reactor, ssl
715 from twisted.words.protocols.jabber.jid import JID
716 from twisted.words.xish import domish
717@@ -39,27 +39,48 @@
718 for room in self.parent.rooms:
719 self.join(room)
720
721+ event = Event(self.parent.name, u'source')
722+ event.status = u'connected'
723+ ibid.dispatcher.dispatch(event)
724+
725+ def connectionLost(self, reason):
726+ self.parent.log.info(u"Disconnected (%s)", reason)
727+
728+ event = Event(self.parent.name, u'source')
729+ event.status = u'disconnected'
730+ ibid.dispatcher.dispatch(event)
731+
732+ subprotocols.XMPPHandler.connectionLost(self, reason)
733+
734+ def _state_event(self, entity, state):
735+ event = Event(self.name, u'state')
736+ event.state = state
737+ if entity.userhost().lower() in self.rooms:
738+ nick = entity.full().split('/')[1]
739+ event.channel = entity.userhost()
740+ if nick == self.parent.nick:
741+ event.type = u'connection'
742+ event.status = state == u'online' and u'joined' or u'left'
743+ else:
744+ event.sender['connection'] = entity.full()
745+ event.sender['id'] = event.sender['connection']
746+ event.sender['nick'] = nick
747+ event.public = True
748+ else:
749+ event.sender['connection'] = entity.full()
750+ event.sender['id'] = event.sender['connection'].split('/')[0]
751+ event.sender['nick'] = event.sender['connection'].split('@')[0]
752+ event.channel = entity.full()
753+ event.public = False
754+ ibid.dispatcher.dispatch(event).addCallback(self.respond)
755+
756 def availableReceived(self, entity, show=None, statuses=None, priority=0):
757- event = Event(self.name, u'state')
758- event.sender['connection'] = entity.full()
759- event.sender['id'] = event.sender['connection'].split('/')[0]
760- event.sender['nick'] = event.sender['connection'].split('@')[0]
761- event.state = show or u'online'
762- event.public = False
763- event.channel = entity.full()
764- self.parent.log.debug(u"Received available presence from %s (%s)", event.sender['connection'], event.state)
765- ibid.dispatcher.dispatch(event).addCallback(self.respond)
766+ self.parent.log.debug(u"Received available presence from %s (%s)", entity.full(), show)
767+ self._state_event(entity, u'online')
768
769 def unavailableReceived(self, entity, statuses):
770- event = Event(self.name, u'state')
771- event.sender['connection'] = entity.full()
772- event.sender['id'] = event.sender['connection'].split('/')[0]
773- event.sender['nick'] = event.sender['connection'].split('@')[0]
774- event.state = u'offline'
775- event.public = False
776- event.channel = entity.full()
777- self.parent.log.debug(u"Received unavailable presence from %s", event.sender['connection'])
778- ibid.dispatcher.dispatch(event).addCallback(self.respond)
779+ self.parent.log.debug(u"Received unavailable presence from %s", entity.full())
780+ self._state_event(entity, u'offline')
781
782 def subscribeReceived(self, entity):
783 response = xmppim.Presence(to=entity, type='subscribed')
784@@ -121,18 +142,18 @@
785 self.parent.log.debug(u"Sent %s message to %s: %s", message['type'], message['to'], message.body)
786
787 def join(self, room):
788+ self.parent.log.info(u"Joining %s", room)
789 jid = JID('%s/%s' % (room, self.parent.nick))
790 presence = xmppim.AvailablePresence(to=jid)
791 self.xmlstream.send(presence)
792- self.rooms.append(room)
793- self.parent.log.info(u"Joining %s", room)
794+ self.rooms.append(room.lower())
795
796- def part(self, room):
797+ def leave(self, room):
798+ self.parent.log.info(u"Leaving %s", room)
799 jid = JID('%s/%s' % (room, self.parent.nick))
800 presence = xmppim.UnavailablePresence(to=jid)
801 self.xmlstream.send(presence)
802- self.rooms.remove(room)
803- self.parent.log.info(u"Leaving %s", room)
804+ self.rooms.remove(room.lower())
805
806 class SourceFactory(client.DeferredClientFactory, IbidSourceFactory):
807
808@@ -182,8 +203,8 @@
809 def join(self, room):
810 return self.proto.join(room)
811
812- def part(self, room):
813- return self.proto.part(room)
814+ def leave(self, room):
815+ return self.proto.leave(room)
816
817 def url(self):
818 return u'xmpp://%s' % (self.jid_str,)
819
820=== modified file 'ibid/source/silc.py'
821--- ibid/source/silc.py 2009-12-30 18:34:43 +0000
822+++ ibid/source/silc.py 2009-12-30 22:21:13 +0000
823@@ -20,7 +20,7 @@
824 self.users = {}
825
826 self.factory.join = self.join
827- self.factory.part = self.part
828+ self.factory.leave = self.leave
829 self.factory.send = self.send
830
831 def _create_event(self, type, user, channel):
832@@ -34,7 +34,6 @@
833 else:
834 event.channel = event.sender['connection']
835 event.public = True
836- event.source = self.factory.name
837
838 self.users[event.sender['connection']] = user
839 self.users[event.sender['id']] = user
840@@ -115,7 +114,7 @@
841 self.command_call('JOIN %s' % channel)
842 return True
843
844- def part(self, channel):
845+ def leave(self, channel):
846 if channel not in self.channels:
847 return False
848
849@@ -147,6 +146,19 @@
850 del self.users[self._to_hex(user.user_id)]
851 del self.users[self._to_hex(user.fingerprint)]
852
853+ def notify_nick_change(self, user, old_nick, new_nick):
854+ event = self._create_event(u'state', user, None)
855+ event.state = u'offline'
856+ event.sender['nick'] = unicode(old_nick, 'utf-8', 'replace')
857+ event.othername = unicode(new_nick, 'utf-8', 'replace')
858+ ibid.dispatcher.dispatch(event).addCallback(self.respond)
859+
860+ event = self._create_event(u'state', user, None)
861+ event.state = u'online'
862+ event.sender['nick'] = unicode(new_nick, 'utf-8', 'replace')
863+ event.othername = unicode(old_nick, 'utf-8', 'replace')
864+ ibid.dispatcher.dispatch(event).addCallback(self.respond)
865+
866 def notify_kicked(self, user, message, kicker, channel):
867 self._state_event(user, channel, u'kicked', kicker, message)
868
869@@ -162,13 +174,25 @@
870 for channel in self.factory.channels:
871 self.join(channel)
872
873+ event = Event(self.factory.name, u'source')
874+ event.status = u'connected'
875+ ibid.dispatcher.dispatch(event)
876+
877 def command_reply_join(self, channel, name, topic, hmac, x, y, users):
878 self.channels[name] = channel
879+ for user in users:
880+ self._state_event(user, channel, u'online')
881
882 def disconnect(self):
883 self.command_call('QUIT')
884
885 def disconnected(self, message):
886+ self.factory.log.info(u"Disconnected (%s)", reason)
887+
888+ event = Event(self.factory.name, u'source')
889+ event.status = u'disconnected'
890+ ibid.dispatcher.dispatch(event)
891+
892 self.factory.s.stopService()
893 self.channels.clear()
894 self.users.clear()

Subscribers

People subscribed via source and target branches