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,
105 def getGroupConversation(self, name, hide=0):
106 name=string.lower(name)
107 return self.chat.getGroupConversation(self.chat.getGroup(name, self),
110 def getPerson(self,name):
111 return self.chat.getPerson(name, self)
113 def connectionMade(self):
114 # XXX: Why do I duplicate code in IRCClient.register?
116 print 'connection made on irc service!?', self
117 if self.account.password:
118 self.sendLine("PASS :%s" % self.account.password)
119 self.setNick(self.account.username)
120 self.sendLine("USER %s foo bar :dreamIRC e2 v1.0 user" % (self.nickname))
121 for channel in self.account.channels:
122 print "joining channel: %s" % channel
123 self.joinGroup(channel)
124 self.account._isOnline=1
125 print 'uh, registering irc acct'
126 if self._logonDeferred is not None:
127 self._logonDeferred.callback(self)
128 self.chat.getContactsList()
131 traceback.print_exc()
133 def setNick(self,nick):
135 self.accountName="%s (IRC)"%nick
136 irc.IRCClient.setNick(self,nick)
138 def quit(self,message='bye bye'):
139 # self.quit_str=str("QUIT :%s" % message)
140 self.sendLine("QUIT :%s" % message)
142 def kickedFrom(self, channel, kicker, message):
143 """Called when I am kicked from a channel.
145 print 'wow i was kicked', channel, kicker, message
146 return self.chat.getGroupConversation(
147 self.chat.getGroup(channel[1:], self), 1)
149 def userKicked(self, kickee, channel, kicker, message):
150 print 'whew somebody else', kickee, channel, kicker, message
152 def noticed(self, username, channel, message):
153 self.privmsg(username, channel, message, {"dontAutoRespond": 1})
155 def privmsg(self, username, channel, message, metadata=None):
158 username=string.split(username,'!',1)[0]
159 if username==self.name: return
162 self.getGroupConversation(group).showGroupMessage(username, message, metadata)
164 self.chat.getConversation(self.getPerson(username)).showMessage(message, metadata)
166 def action(self,username,channel,emote):
167 username=string.split(username,'!',1)[0]
168 if username==self.name: return
169 meta={'style':'emote'}
172 self.getGroupConversation(group).showGroupMessage(username, emote, meta)
174 self.chat.getConversation(self.getPerson(username)).showMessage(emote,meta)
176 def irc_RPL_NAMREPLY(self,prefix,params):
180 << :Arlington.VA.US.Undernet.Org 353 z3p = #bnl :pSwede Dan-- SkOyg AG
182 group=string.lower(params[2][1:])
183 users=string.split(params[3])
184 for ui in range(len(users)):
185 while users[ui][0] in ["@","+"]: # channel modes
186 users[ui]=users[ui][1:]
187 if not self._namreplies.has_key(group):
188 self._namreplies[group]=[]
189 self._namreplies[group].extend(users)
190 for nickname in users:
192 self._ingroups[nickname].append(group)
194 self._ingroups[nickname]=[group]
196 def irc_RPL_ENDOFNAMES(self,prefix,params):
198 self.getGroupConversation(group).setGroupMembers(self._namreplies[string.lower(group)])
199 del self._namreplies[string.lower(group)]
201 def irc_RPL_TOPIC(self,prefix,params):
202 self._topics[params[1][1:]]=params[2]
204 def irc_333(self,prefix,params):
206 self.getGroupConversation(group).setTopic(self._topics[group],params[2])
207 del self._topics[group]
209 def irc_TOPIC(self,prefix,params):
210 nickname = string.split(prefix,"!")[0]
211 group = params[0][1:]
213 self.getGroupConversation(group).setTopic(topic,nickname)
215 def irc_JOIN(self,prefix,params):
216 nickname=string.split(prefix,"!")[0]
217 group=string.lower(params[0][1:])
218 if nickname!=self.nickname:
220 self._ingroups[nickname].append(group)
222 self._ingroups[nickname]=[group]
223 self.getGroupConversation(group).memberJoined(nickname)
225 def irc_PART(self,prefix,params):
226 nickname=string.split(prefix,"!")[0]
227 group=string.lower(params[0][1:])
228 if nickname!=self.nickname:
229 if group in self._ingroups[nickname]:
230 self._ingroups[nickname].remove(group)
231 self.getGroupConversation(group).memberLeft(nickname)
233 print "%s left %s, but wasn't in the room."%(nickname,group)
235 def irc_QUIT(self,prefix,params):
236 nickname=string.split(prefix,"!")[0]
237 if self._ingroups.has_key(nickname):
238 for group in self._ingroups[nickname]:
239 self.getGroupConversation(group).memberLeft(nickname)
240 self._ingroups[nickname]=[]
242 print '*** WARNING: ingroups had no such key %s' % nickname
244 def irc_NICK(self, prefix, params):
245 fromNick = string.split(prefix, "!")[0]
247 if not self._ingroups.has_key(fromNick):
248 print "%s changed nick to %s. But she's not in any groups!?" % (fromNick, toNick)
250 for group in self._ingroups[fromNick]:
251 self.getGroupConversation(group).memberChangedNick(fromNick, toNick)
252 self._ingroups[toNick] = self._ingroups[fromNick]
253 del self._ingroups[fromNick]
255 def irc_unknown(self, prefix, command, params):
256 print "unknown message from IRCserver. prefix: %s, command: %s, params: %s" % (prefix, command, params)
259 def joinGroup(self,name):
261 self.getGroupConversation(name)
263 class IRCAccount(e2support.AbstractAccount):
264 implements(interfaces.IAccount)
267 _groupFactory = IRCGroup
268 _personFactory = IRCPerson
270 def __init__(self, accountName, autoLogin, username, password, host, port, channels=''):
271 e2support.AbstractAccount.__init__(self, accountName, autoLogin, username, password, host, port)
272 self.channels = map(string.strip,string.split(channels,','))
273 if self.channels == ['']:
276 def _startLogOn(self, chatui):
277 logonDeferred = defer.Deferred()
278 cc = protocol.ClientCreator(reactor, IRCProto, self, chatui, logonDeferred)
279 d = cc.connectTCP(self.host, self.port)
280 d.addErrback(logonDeferred.errback)