root/trunk/twisted/words/im/basesupport.py

Revision 30752, 7.7 KB (checked in by exarkun, 15 months ago)

Rewrite the copyright headers to exclude date information.

Author: exarkun
Reviewer: glyph
Fixes: #4857

To avoid the need to perpetually update copyright dates in each file in Twisted,
remove the dates from most files and just leave them in the LICENSE file.

As a side effect, some files also have had a trailing newline added where it was
missing before.

Line 
1# Copyright (c) Twisted Matrix Laboratories.
2# See LICENSE for details.
3
4#
5
6"""Instance Messenger base classes for protocol support.
7
8You will find these useful if you're adding a new protocol to IM.
9"""
10
11# Abstract representation of chat "model" classes
12
13from twisted.words.im.locals import ONLINE, OFFLINE, OfflineError
14from twisted.words.im import interfaces
15
16from twisted.internet.protocol import Protocol
17
18from twisted.python.reflect import prefixedMethods
19from twisted.persisted import styles
20
21from twisted.internet import error
22
23class AbstractGroup:
24    def __init__(self, name, account):
25        self.name = name
26        self.account = account
27
28    def getGroupCommands(self):
29        """finds group commands
30
31        these commands are methods on me that start with imgroup_; they are
32        called with no arguments
33        """
34        return prefixedMethods(self, "imgroup_")
35
36    def getTargetCommands(self, target):
37        """finds group commands
38
39        these commands are methods on me that start with imgroup_; they are
40        called with a user present within this room as an argument
41
42        you may want to override this in your group in order to filter for
43        appropriate commands on the given user
44        """
45        return prefixedMethods(self, "imtarget_")
46
47    def join(self):
48        if not self.account.client:
49            raise OfflineError
50        self.account.client.joinGroup(self.name)
51
52    def leave(self):
53        if not self.account.client:
54            raise OfflineError
55        self.account.client.leaveGroup(self.name)
56
57    def __repr__(self):
58        return '<%s %r>' % (self.__class__, self.name)
59
60    def __str__(self):
61        return '%s@%s' % (self.name, self.account.accountName)
62
63class AbstractPerson:
64    def __init__(self, name, baseAccount):
65        self.name = name
66        self.account = baseAccount
67        self.status = OFFLINE
68
69    def getPersonCommands(self):
70        """finds person commands
71
72        these commands are methods on me that start with imperson_; they are
73        called with no arguments
74        """
75        return prefixedMethods(self, "imperson_")
76
77    def getIdleTime(self):
78        """
79        Returns a string.
80        """
81        return '--'
82
83    def __repr__(self):
84        return '<%s %r/%s>' % (self.__class__, self.name, self.status)
85
86    def __str__(self):
87        return '%s@%s' % (self.name, self.account.accountName)
88
89class AbstractClientMixin:
90    """Designed to be mixed in to a Protocol implementing class.
91
92    Inherit from me first.
93
94    @ivar _logonDeferred: Fired when I am done logging in.
95    """
96    def __init__(self, account, chatui, logonDeferred):
97        for base in self.__class__.__bases__:
98            if issubclass(base, Protocol):
99                self.__class__._protoBase = base
100                break
101        else:
102            pass
103        self.account = account
104        self.chat = chatui
105        self._logonDeferred = logonDeferred
106
107    def connectionMade(self):
108        self._protoBase.connectionMade(self)
109
110    def connectionLost(self, reason):
111        self.account._clientLost(self, reason)
112        self.unregisterAsAccountClient()
113        return self._protoBase.connectionLost(self, reason)
114
115    def unregisterAsAccountClient(self):
116        """Tell the chat UI that I have `signed off'.
117        """
118        self.chat.unregisterAccountClient(self)
119
120
121class AbstractAccount(styles.Versioned):
122    """Base class for Accounts.
123
124    I am the start of an implementation of L{IAccount<interfaces.IAccount>}, I
125    implement L{isOnline} and most of L{logOn}, though you'll need to implement
126    L{_startLogOn} in a subclass.
127
128    @cvar _groupFactory: A Callable that will return a L{IGroup} appropriate
129        for this account type.
130    @cvar _personFactory: A Callable that will return a L{IPerson} appropriate
131        for this account type.
132
133    @type _isConnecting: boolean
134    @ivar _isConnecting: Whether I am in the process of establishing a
135    connection to the server.
136    @type _isOnline: boolean
137    @ivar _isOnline: Whether I am currently on-line with the server.
138
139    @ivar accountName:
140    @ivar autoLogin:
141    @ivar username:
142    @ivar password:
143    @ivar host:
144    @ivar port:
145    """
146
147    _isOnline = 0
148    _isConnecting = 0
149    client = None
150
151    _groupFactory = AbstractGroup
152    _personFactory = AbstractPerson
153
154    persistanceVersion = 2
155
156    def __init__(self, accountName, autoLogin, username, password, host, port):
157        self.accountName = accountName
158        self.autoLogin = autoLogin
159        self.username = username
160        self.password = password
161        self.host = host
162        self.port = port
163
164        self._groups = {}
165        self._persons = {}
166
167    def upgrateToVersion2(self):
168        # Added in CVS revision 1.16.
169        for k in ('_groups', '_persons'):
170            if not hasattr(self, k):
171                setattr(self, k, {})
172
173    def __getstate__(self):
174        state = styles.Versioned.__getstate__(self)
175        for k in ('client', '_isOnline', '_isConnecting'):
176            try:
177                del state[k]
178            except KeyError:
179                pass
180        return state
181
182    def isOnline(self):
183        return self._isOnline
184
185    def logOn(self, chatui):
186        """Log on to this account.
187
188        Takes care to not start a connection if a connection is
189        already in progress.  You will need to implement
190        L{_startLogOn} for this to work, and it would be a good idea
191        to override L{_loginFailed} too.
192
193        @returntype: Deferred L{interfaces.IClient}
194        """
195        if (not self._isConnecting) and (not self._isOnline):
196            self._isConnecting = 1
197            d = self._startLogOn(chatui)
198            d.addCallback(self._cb_logOn)
199            # if chatui is not None:
200            # (I don't particularly like having to pass chatUI to this function,
201            # but we haven't factored it out yet.)
202            d.addCallback(chatui.registerAccountClient)
203            d.addErrback(self._loginFailed)
204            return d
205        else:
206            raise error.ConnectError("Connection in progress")
207
208    def getGroup(self, name):
209        """Group factory.
210
211        @param name: Name of the group on this account.
212        @type name: string
213        """
214        group = self._groups.get(name)
215        if group is None:
216            group = self._groupFactory(name, self)
217            self._groups[name] = group
218        return group
219
220    def getPerson(self, name):
221        """Person factory.
222
223        @param name: Name of the person on this account.
224        @type name: string
225        """
226        person = self._persons.get(name)
227        if person is None:
228            person = self._personFactory(name, self)
229            self._persons[name] = person
230        return person
231
232    def _startLogOn(self, chatui):
233        """Start the sign on process.
234
235        Factored out of L{logOn}.
236
237        @returntype: Deferred L{interfaces.IClient}
238        """
239        raise NotImplementedError()
240
241    def _cb_logOn(self, client):
242        self._isConnecting = 0
243        self._isOnline = 1
244        self.client = client
245        return client
246
247    def _loginFailed(self, reason):
248        """Errorback for L{logOn}.
249
250        @type reason: Failure
251
252        @returns: I{reason}, for further processing in the callback chain.
253        @returntype: Failure
254        """
255        self._isConnecting = 0
256        self._isOnline = 0 # just in case
257        return reason
258
259    def _clientLost(self, client, reason):
260        self.client = None
261        self._isConnecting = 0
262        self._isOnline = 0
263        return reason
264
265    def __repr__(self):
266        return "<%s: %s (%s@%s:%s)>" % (self.__class__,
267                                        self.accountName,
268                                        self.username,
269                                        self.host,
270                                        self.port)
Note: See TracBrowser for help on using the browser.