~landscape/zope3/newer-from-ztk

« back to all changes in this revision

Viewing changes to src/twisted/words/im/pbsupport.py

  • Committer: Thomas Hervé
  • Date: 2009-07-08 13:52:04 UTC
  • Revision ID: thomas@canonical.com-20090708135204-df5eesrthifpylf8
Remove twisted copy

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
2
 
# See LICENSE for details.
3
 
 
4
 
 
5
 
"""L{twisted.words} support for Instance Messenger."""
6
 
 
7
 
from __future__ import nested_scopes
8
 
 
9
 
from twisted.internet import defer
10
 
from twisted.internet import error
11
 
from twisted.python import log
12
 
from twisted.python.failure import Failure
13
 
from twisted.spread import pb
14
 
 
15
 
from twisted.words.im.locals import ONLINE, OFFLINE, AWAY
16
 
 
17
 
from twisted.words.im import basesupport, interfaces
18
 
from zope.interface import implements
19
 
 
20
 
 
21
 
class TwistedWordsPerson(basesupport.AbstractPerson):
22
 
    """I a facade for a person you can talk to through a twisted.words service.
23
 
    """
24
 
    def __init__(self, name, wordsAccount):
25
 
        basesupport.AbstractPerson.__init__(self, name, wordsAccount)
26
 
        self.status = OFFLINE
27
 
 
28
 
    def isOnline(self):
29
 
        return ((self.status == ONLINE) or
30
 
                (self.status == AWAY))
31
 
 
32
 
    def getStatus(self):
33
 
        return self.status
34
 
 
35
 
    def sendMessage(self, text, metadata):
36
 
        """Return a deferred...
37
 
        """
38
 
        if metadata:
39
 
            d=self.account.client.perspective.directMessage(self.name,
40
 
                                                            text, metadata)
41
 
            d.addErrback(self.metadataFailed, "* "+text)
42
 
            return d
43
 
        else:
44
 
            return self.account.client.perspective.callRemote('directMessage',self.name, text)
45
 
 
46
 
    def metadataFailed(self, result, text):
47
 
        print "result:",result,"text:",text
48
 
        return self.account.client.perspective.directMessage(self.name, text)
49
 
 
50
 
    def setStatus(self, status):
51
 
        self.status = status
52
 
        self.chat.getContactsList().setContactStatus(self)
53
 
 
54
 
class TwistedWordsGroup(basesupport.AbstractGroup):
55
 
    implements(interfaces.IGroup)
56
 
    def __init__(self, name, wordsClient):
57
 
        basesupport.AbstractGroup.__init__(self, name, wordsClient)
58
 
        self.joined = 0
59
 
 
60
 
    def sendGroupMessage(self, text, metadata=None):
61
 
        """Return a deferred.
62
 
        """
63
 
        #for backwards compatibility with older twisted.words servers.
64
 
        if metadata:
65
 
            d=self.account.client.perspective.callRemote(
66
 
                'groupMessage', self.name, text, metadata)
67
 
            d.addErrback(self.metadataFailed, "* "+text)
68
 
            return d
69
 
        else:
70
 
            return self.account.client.perspective.callRemote('groupMessage',
71
 
                                                              self.name, text)
72
 
 
73
 
    def setTopic(self, text):
74
 
        self.account.client.perspective.callRemote(
75
 
            'setGroupMetadata',
76
 
            {'topic': text, 'topic_author': self.client.name},
77
 
            self.name)
78
 
 
79
 
    def metadataFailed(self, result, text):
80
 
        print "result:",result,"text:",text
81
 
        return self.account.client.perspective.callRemote('groupMessage',
82
 
                                                          self.name, text)
83
 
 
84
 
    def joining(self):
85
 
        self.joined = 1
86
 
 
87
 
    def leaving(self):
88
 
        self.joined = 0
89
 
 
90
 
    def leave(self):
91
 
        return self.account.client.perspective.callRemote('leaveGroup',
92
 
                                                          self.name)
93
 
 
94
 
 
95
 
 
96
 
class TwistedWordsClient(pb.Referenceable, basesupport.AbstractClientMixin):
97
 
    """In some cases, this acts as an Account, since it a source of text
98
 
    messages (multiple Words instances may be on a single PB connection)
99
 
    """
100
 
    def __init__(self, acct, serviceName, perspectiveName, chatui,
101
 
                 _logonDeferred=None):
102
 
        self.accountName = "%s (%s:%s)" % (acct.accountName, serviceName, perspectiveName)
103
 
        self.name = perspectiveName
104
 
        print "HELLO I AM A PB SERVICE", serviceName, perspectiveName
105
 
        self.chat = chatui
106
 
        self.account = acct
107
 
        self._logonDeferred = _logonDeferred
108
 
 
109
 
    def getPerson(self, name):
110
 
        return self.chat.getPerson(name, self)
111
 
 
112
 
    def getGroup(self, name):
113
 
        return self.chat.getGroup(name, self)
114
 
 
115
 
    def getGroupConversation(self, name):
116
 
        return self.chat.getGroupConversation(self.getGroup(name))
117
 
 
118
 
    def addContact(self, name):
119
 
        self.perspective.callRemote('addContact', name)
120
 
 
121
 
    def remote_receiveGroupMembers(self, names, group):
122
 
        print 'received group members:', names, group
123
 
        self.getGroupConversation(group).setGroupMembers(names)
124
 
 
125
 
    def remote_receiveGroupMessage(self, sender, group, message, metadata=None):
126
 
        print 'received a group message', sender, group, message, metadata
127
 
        self.getGroupConversation(group).showGroupMessage(sender, message, metadata)
128
 
 
129
 
    def remote_memberJoined(self, member, group):
130
 
        print 'member joined', member, group
131
 
        self.getGroupConversation(group).memberJoined(member)
132
 
 
133
 
    def remote_memberLeft(self, member, group):
134
 
        print 'member left'
135
 
        self.getGroupConversation(group).memberLeft(member)
136
 
 
137
 
    def remote_notifyStatusChanged(self, name, status):
138
 
        self.chat.getPerson(name, self).setStatus(status)
139
 
 
140
 
    def remote_receiveDirectMessage(self, name, message, metadata=None):
141
 
        self.chat.getConversation(self.chat.getPerson(name, self)).showMessage(message, metadata)
142
 
 
143
 
    def remote_receiveContactList(self, clist):
144
 
        for name, status in clist:
145
 
            self.chat.getPerson(name, self).setStatus(status)
146
 
 
147
 
    def remote_setGroupMetadata(self, dict_, groupName):
148
 
        if dict_.has_key("topic"):
149
 
            self.getGroupConversation(groupName).setTopic(dict_["topic"], dict_.get("topic_author", None))
150
 
 
151
 
    def joinGroup(self, name):
152
 
        self.getGroup(name).joining()
153
 
        return self.perspective.callRemote('joinGroup', name).addCallback(self._cbGroupJoined, name)
154
 
 
155
 
    def leaveGroup(self, name):
156
 
        self.getGroup(name).leaving()
157
 
        return self.perspective.callRemote('leaveGroup', name).addCallback(self._cbGroupLeft, name)
158
 
 
159
 
    def _cbGroupJoined(self, result, name):
160
 
        groupConv = self.chat.getGroupConversation(self.getGroup(name))
161
 
        groupConv.showGroupMessage("sys", "you joined")
162
 
        self.perspective.callRemote('getGroupMembers', name)
163
 
 
164
 
    def _cbGroupLeft(self, result, name):
165
 
        print 'left',name
166
 
        groupConv = self.chat.getGroupConversation(self.getGroup(name), 1)
167
 
        groupConv.showGroupMessage("sys", "you left")
168
 
 
169
 
    def connected(self, perspective):
170
 
        print 'Connected Words Client!', perspective
171
 
        if self._logonDeferred is not None:
172
 
            self._logonDeferred.callback(self)
173
 
        self.perspective = perspective
174
 
        self.chat.getContactsList()
175
 
 
176
 
 
177
 
pbFrontEnds = {
178
 
    "twisted.words": TwistedWordsClient,
179
 
    "twisted.reality": None
180
 
    }
181
 
 
182
 
 
183
 
class PBAccount(basesupport.AbstractAccount):
184
 
    implements(interfaces.IAccount)
185
 
    gatewayType = "PB"
186
 
    _groupFactory = TwistedWordsGroup
187
 
    _personFactory = TwistedWordsPerson
188
 
 
189
 
    def __init__(self, accountName, autoLogin, username, password, host, port,
190
 
                 services=None):
191
 
        """
192
 
        @param username: The name of your PB Identity.
193
 
        @type username: string
194
 
        """
195
 
        basesupport.AbstractAccount.__init__(self, accountName, autoLogin,
196
 
                                             username, password, host, port)
197
 
        self.services = []
198
 
        if not services:
199
 
            services = [('twisted.words', 'twisted.words', username)]
200
 
        for serviceType, serviceName, perspectiveName in services:
201
 
            self.services.append([pbFrontEnds[serviceType], serviceName,
202
 
                                  perspectiveName])
203
 
 
204
 
    def logOn(self, chatui):
205
 
        """
206
 
        @returns: this breaks with L{interfaces.IAccount}
207
 
        @returntype: DeferredList of L{interfaces.IClient}s
208
 
        """
209
 
        # Overriding basesupport's implementation on account of the
210
 
        # fact that _startLogOn tends to return a deferredList rather
211
 
        # than a simple Deferred, and we need to do registerAccountClient.
212
 
        if (not self._isConnecting) and (not self._isOnline):
213
 
            self._isConnecting = 1
214
 
            d = self._startLogOn(chatui)
215
 
            d.addErrback(self._loginFailed)
216
 
            def registerMany(results):
217
 
                for success, result in results:
218
 
                    if success:
219
 
                        chatui.registerAccountClient(result)
220
 
                        self._cb_logOn(result)
221
 
                    else:
222
 
                        log.err(result)
223
 
            d.addCallback(registerMany)
224
 
            return d
225
 
        else:
226
 
            raise error.ConnectionError("Connection in progress")
227
 
 
228
 
 
229
 
    def _startLogOn(self, chatui):
230
 
        print 'Connecting...',
231
 
        d = pb.getObjectAt(self.host, self.port)
232
 
        d.addCallbacks(self._cbConnected, self._ebConnected,
233
 
                       callbackArgs=(chatui,))
234
 
        return d
235
 
 
236
 
    def _cbConnected(self, root, chatui):
237
 
        print 'Connected!'
238
 
        print 'Identifying...',
239
 
        d = pb.authIdentity(root, self.username, self.password)
240
 
        d.addCallbacks(self._cbIdent, self._ebConnected,
241
 
                       callbackArgs=(chatui,))
242
 
        return d
243
 
 
244
 
    def _cbIdent(self, ident, chatui):
245
 
        if not ident:
246
 
            print 'falsely identified.'
247
 
            return self._ebConnected(Failure(Exception("username or password incorrect")))
248
 
        print 'Identified!'
249
 
        dl = []
250
 
        for handlerClass, sname, pname in self.services:
251
 
            d = defer.Deferred()
252
 
            dl.append(d)
253
 
            handler = handlerClass(self, sname, pname, chatui, d)
254
 
            ident.callRemote('attach', sname, pname, handler).addCallback(handler.connected)
255
 
        return defer.DeferredList(dl)
256
 
 
257
 
    def _ebConnected(self, error):
258
 
        print 'Not connected.'
259
 
        return error
260