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