1 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
2 # See LICENSE for details.
5 """IRC support for Instance Messenger."""
9 from protocols import irc
10 from twisted.internet import defer, reactor, protocol
11 from twisted.internet.defer import succeed
12 import e2support, interfaces,dreamIRCTools
13 from zope.interface import implements
15 class IRCPerson(e2support.AbstractPerson):
17 def imperson_whois(self):
18 if self.account.client is None:
20 self.account.client.sendLine("WHOIS %s" % self.name)
30 def setStatus(self,status):
32 self.chat.getContactsList().setContactStatus(self)
34 def sendMessage(self, text, meta=None):
35 if self.account.client is None:
37 for line in string.split(text, '\n'):
38 if meta and meta.get("style", None) == "emote":
39 self.account.client.ctcpMakeQuery(self.name,[('ACTION', line)])
41 self.account.client.msg(self.name, line)
45 if self.account.client is None:
48 self.account.client.quit("user logged off")
51 class IRCGroup(e2support.AbstractGroup):
53 implements(interfaces.IGroup)
55 def imgroup_testAction(self):
58 def imtarget_kick(self, target):
59 if self.account.client is None:
61 reason = "... and justice for all!"
62 self.account.client.sendLine("KICK #%s %s :%s" % (
63 self.name, target.name, reason))
65 ### Interface Implementation
67 def setTopic(self, topic):
68 if self.account.client is None:
70 self.account.client.topic(self.name, topic)
72 def sendGroupMessage(self, text, meta={}):
73 if self.account.client is None:
75 if meta and meta.get("style", None) == "emote":
76 self.account.client.me(self.name,text)
78 #standard shmandard, clients don't support plain escaped newlines!
79 for line in string.split(text, '\n'):
80 self.account.client.say(self.name, line)
84 if self.account.client is None:
86 self.account.client.leave(self.name)
87 self.account.client.getGroupConversation(self.name,1)
90 if self.account.client is None:
93 self.account.client.quit("user logged off")
96 class IRCProto(e2support.AbstractClientMixin, irc.IRCClient):
97 def __init__(self, account, chatui, logonDeferred=None):
98 e2support.AbstractClientMixin.__init__(self, account, chatui,
104 self.pipe = dreamIRCTools.MessagePipe()
106 def getGroupConversation(self, name, hide=0):
107 name=string.lower(name)
108 return self.chat.getGroupConversation(self.chat.getGroup(name, self),
111 def getPerson(self,name):
112 return self.chat.getPerson(name, self)
114 def connectionMade(self):
115 # XXX: Why do I duplicate code in IRCClient.register?
117 print 'connection made on irc service!?', self
118 self.pipe.debug("connection made on irc service!?")
119 if self.account.password:
120 self.sendLine("PASS :%s" % self.account.password)
121 self.setNick(self.account.username)
122 self.sendLine("USER %s foo bar :dreamIRC e2 v1.0 user" % (self.nickname))
123 for channel in self.account.channels:
124 self.pipe.debug("joining channel: %s" % channel)
125 self.joinGroup(channel)
126 self.account._isOnline=1
127 self.pipe.debug("uh, registering irc acct")
128 if self._logonDeferred is not None:
129 self._logonDeferred.callback(self)
130 self.chat.getContactsList()
133 traceback.print_exc()
135 def setNick(self,nick):
137 self.accountName="%s (IRC)"%nick
138 irc.IRCClient.setNick(self,nick)
140 def quit(self,message='bye bye'):
141 # self.quit_str=str("QUIT :%s" % message)
142 self.sendLine("QUIT :%s" % message)
144 def kickedFrom(self, channel, kicker, message):
145 """Called when I am kicked from a channel.
147 self.pipe.debug('wow i was kicked form %s by %s cause of %s' % (channel, kicker, message))
148 return self.chat.getGroupConversation(
149 self.chat.getGroup(channel[1:], self), 1)
151 def userKicked(self, kickee, channel, kicker, message):
152 self.pipe.debug('whew somebody else %s %s %s %s' % (kickee, channel, kicker, message))
154 def noticed(self, username, channel, message):
155 self.privmsg(username, channel, message, {"dontAutoRespond": 1})
157 def privmsg(self, username, channel, message, metadata=None):
160 username=string.split(username,'!',1)[0]
161 if username==self.name: return
164 self.getGroupConversation(group).showGroupMessage(username, message, metadata)
166 self.chat.getConversation(self.getPerson(username)).showMessage(message, metadata)
168 def action(self,username,channel,emote):
169 username=string.split(username,'!',1)[0]
170 if username==self.name: return
171 meta={'style':'emote'}
174 self.getGroupConversation(group).showGroupMessage(username, emote, meta)
176 self.chat.getConversation(self.getPerson(username)).showMessage(emote,meta)
178 def irc_RPL_NAMREPLY(self,prefix,params):
182 << :Arlington.VA.US.Undernet.Org 353 z3p = #bnl :pSwede Dan-- SkOyg AG
184 group=string.lower(params[2][1:])
185 users=string.split(params[3])
186 for ui in range(len(users)):
187 while users[ui][0] in ["@","+"]: # channel modes
188 users[ui]=users[ui][1:]
189 if not self._namreplies.has_key(group):
190 self._namreplies[group]=[]
191 self._namreplies[group].extend(users)
192 for nickname in users:
194 self._ingroups[nickname].append(group)
196 self._ingroups[nickname]=[group]
198 def irc_RPL_ENDOFNAMES(self,prefix,params):
200 self.getGroupConversation(group).setGroupMembers(self._namreplies[string.lower(group)])
201 del self._namreplies[string.lower(group)]
203 def irc_RPL_TOPIC(self,prefix,params):
204 self._topics[params[1][1:]]=params[2]
206 def irc_333(self,prefix,params):
208 self.getGroupConversation(group).setTopic(self._topics[group],params[2])
209 del self._topics[group]
211 def irc_TOPIC(self,prefix,params):
212 nickname = string.split(prefix,"!")[0]
213 group = params[0][1:]
215 self.getGroupConversation(group).setTopic(topic,nickname)
217 def irc_JOIN(self,prefix,params):
218 nickname=string.split(prefix,"!")[0]
219 group=string.lower(params[0][1:])
220 if nickname!=self.nickname:
222 self._ingroups[nickname].append(group)
224 self._ingroups[nickname]=[group]
225 self.getGroupConversation(group).memberJoined(nickname)
227 def irc_PART(self,prefix,params):
228 nickname=string.split(prefix,"!")[0]
229 group=string.lower(params[0][1:])
230 if nickname!=self.nickname:
231 if group in self._ingroups[nickname]:
232 self._ingroups[nickname].remove(group)
233 self.getGroupConversation(group).memberLeft(nickname)
235 self.pipe.debug("%s left %s, but wasn't in the room."%(nickname,group))
237 def irc_QUIT(self,prefix,params):
238 nickname=string.split(prefix,"!")[0]
239 if self._ingroups.has_key(nickname):
240 for group in self._ingroups[nickname]:
241 self.getGroupConversation(group).memberLeft(nickname)
242 self._ingroups[nickname]=[]
244 self.pipe.debug('*** WARNING: ingroups had no such key %s' % nickname)
246 def irc_NICK(self, prefix, params):
247 fromNick = string.split(prefix, "!")[0]
249 if not self._ingroups.has_key(fromNick):
250 self.pipe.debug("%s changed nick to %s. But she's not in any groups!?" % (fromNick, toNick))
252 for group in self._ingroups[fromNick]:
253 self.getGroupConversation(group).memberChangedNick(fromNick, toNick)
254 self._ingroups[toNick] = self._ingroups[fromNick]
255 del self._ingroups[fromNick]
257 def irc_unknown(self, prefix, command, params):
258 self.pipe.debug("unknown message from IRCserver. prefix: %s, command: %s, params: %s" % (prefix, command, params))
261 def joinGroup(self,name):
263 self.getGroupConversation(name)
265 class IRCAccount(e2support.AbstractAccount):
266 implements(interfaces.IAccount)
269 _groupFactory = IRCGroup
270 _personFactory = IRCPerson
272 def __init__(self, accountName, autoLogin, username, password, host, port, channels=''):
273 e2support.AbstractAccount.__init__(self, accountName, autoLogin, username, password, host, port)
274 self.channels = map(string.strip,string.split(channels,','))
275 if self.channels == ['']:
278 def _startLogOn(self, chatui):
279 logonDeferred = defer.Deferred()
280 cc = protocol.ClientCreator(reactor, IRCProto, self, chatui, logonDeferred)
281 d = cc.connectTCP(self.host, self.port)
282 d.addErrback(logonDeferred.errback)