dreamIRC initial check-in
[enigma2-plugins.git] / dreamirc / src / e2chat.py
1 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
2 # See LICENSE for details.
3
4 #
5
6 """Base classes for Instance Messenger clients."""
7 from enigma import *
8 from Screens.Screen import Screen
9
10 from Components.Pixmap import *
11 from Components.Pixmap import Pixmap
12 from Components.ActionMap import ActionMap, NumberActionMap
13 from Components.ScrollLabel import ScrollLabel
14 from Components.GUIComponent import *
15 from Components.MenuList import MenuList
16 from Components.Input import Input
17 from Components.Label import Label
18 from Components.config import *
19 from Components.ConfigList import ConfigList
20 from Plugins.Plugin import PluginDescriptor
21 from Tools.NumericalTextInput import *
22 from Tools.Directories import *
23
24 from locals import OFFLINE, ONLINE, AWAY
25 import dreamIRCTools
26 from enigma import *
27 from dreamIRCTools import *
28 #from myScrollLabel import *
29 #from dreamIRCMainMenu import *
30
31 class ContactsList:
32     """A GUI object that displays a contacts list"""
33     def __init__(self, chatui):
34         """
35         @param chatui: ???
36         @type chatui: L{ChatUI}
37         """
38         self.chatui = chatui
39         self.contacts = {}
40         self.onlineContacts = {}
41         self.clients = []
42         
43     def setContactStatus(self, person):
44         """Inform the user that a person's status has changed.
45
46         @type person: L{Person<interfaces.IPerson>}
47         """
48         if not self.contacts.has_key(person.name):
49             self.contacts[person.name] = person
50         if not self.onlineContacts.has_key(person.name) and \
51             (person.status == ONLINE or person.status == AWAY):
52             self.onlineContacts[person.name] = person
53         if self.onlineContacts.has_key(person.name) and \
54            person.status == OFFLINE:
55             del self.onlineContacts[person.name]
56
57     def registerAccountClient(self, client):
58         """Notify the user that an account client has been signed on to.
59
60         @type client: L{Client<interfaces.IClient>}
61         """
62         if not client in self.clients:
63             self.clients.append(client)
64
65     def unregisterAccountClient(self, client):
66         """Notify the user that an account client has been signed off
67         or disconnected from.
68
69         @type client: L{Client<interfaces.IClient>}
70          """
71         if client in self.clients:
72             self.clients.remove(client)
73
74     def contactChangedNick(self, person, newnick):
75         oldname = person.name
76         if self.contacts.has_key(oldname):
77             del self.contacts[oldname]
78             person.name = newnick
79             self.contacts[newnick] = person
80             if self.onlineContacts.has_key(oldname):
81                 del self.onlineContacts[oldname]
82                 self.onlineContacts[newnick] = person
83
84
85 class Conversation:
86     """A GUI window of a conversation with a specific person"""
87     def __init__(self, person, chatui):
88         """
89         @type person: L{Person<interfaces.IPerson>}
90         @type chatui: L{ChatUI}
91         """
92         self.chatui = chatui
93         self.person = person
94         self.pipe = MessagePipe()
95 #        self.blist=ChatWindow()
96         self.timer=eTimer()
97         self.timer.timeout.get().append(self.sendOutPipe)
98         self.timer.start(100)
99
100     def show(self):
101         """Displays the ConversationWindow"""
102  #       raise NotImplementedError("Subclasses must implement this method")
103
104     def hide(self):
105         """Hides the ConversationWindow"""
106 #        raise NotImplementedError("Subclasses must implement this method")
107
108     def sendText(self, text):
109         """Sends text to the person with whom the user is conversing.
110
111         @returntype: L{Deferred<twisted.internet.defer.Deferred>}
112         """
113         self.person.sendMessage(text, None)
114         self.pipe.add("%s" % text)
115         self.pipe.clearOutText()
116 #        print"<%s> %s" % (self.nickname, text)
117
118     def sendOutPipe(self):
119         if len(str(self.pipe.getOutText())) > 0:
120                 if (self.pipe.getOutText()=="/QUIT"):
121                         print "/quit detected...."
122                         self.pipe.clearOutText()
123                         self.person.bye()
124                 else:
125                         print "sending chat : %s" % str(self.pipe.getOutText())
126                         self.sendText(str(self.pipe.getOutText()))
127                         self.pipe.clearOutText()
128             
129     def showMessage(self, text, metadata=None):
130         """Display a message sent from the person with whom she is conversing
131
132         @type text: string
133         @type metadata: dict
134         """
135         self.pipe.add("<%s> %s" % (self.person.name, text))
136 #        raise NotImplementedError("Subclasses must implement this method")
137
138     def contactChangedNick(self, person, newnick):
139         """Change a person's name.
140
141         @type person: L{Person<interfaces.IPerson>}
142         @type newnick: string
143         """
144         self.person.name = newnick
145         self.pipe.add("-!- %s is now known as %s" % (person.name, newnick))
146 #        self.blist.updateBuddyWindow()
147
148     def serverMsg(self, message):
149         """Displays a serverMsg in the group conversation window
150
151         @type message: string
152         """
153         self.pipe.add("-!- %s " % (message))
154 #        self.blist.updateBuddyWindow()
155
156 class GroupConversation:
157     """A conversation with a group of people."""
158     def __init__(self, group, chatui):
159         """
160         @type group: L{Group<interfaces.IGroup>}
161         @param chatui: ???
162         @type chatui: L{ChatUI}
163         """
164         self.chatui = chatui
165         self.group = group
166         self.members = []
167         self.pipe = MessagePipe()
168 #        self.blist=ChatWindow()
169         self.timer=eTimer()
170         self.timer.timeout.get().append(self.sendOutPipe)
171         self.timer.start(100)
172         
173     def show(self):
174         """Displays the GroupConversationWindow."""
175 #        raise NotImplementedError("Subclasses must implement this method")
176
177     def hide(self):
178         """Hides the GroupConversationWindow."""
179 #        raise NotImplementedError("Subclasses must implement this method")
180
181     def sendText(self, text):
182         """Sends text to the group.
183
184         @type text: string
185         @returntype: L{Deferred<twisted.internet.defer.Deferred>}
186         """
187         self.group.sendGroupMessage(text, None)
188         self.pipe.add("%s" % text)
189         self.pipe.clearOutText()
190 #        print "nach im sending nach sending : %s" % str(self.pipe.getOutText())
191         
192     
193     def sendOutPipe(self):
194         if len(str(self.pipe.getOutText())) > 0:
195                 if (self.pipe.getOutText()=="/QUIT"):
196                         print "/quit detected...."
197                         self.pipe.clearOutText()
198                         self.group.bye()
199                 else:
200                         print "sending group chat : %s" % str(self.pipe.getOutText())
201                         self.sendText(str(self.pipe.getOutText()))
202                         self.pipe.clearOutText()
203             
204     def showGroupMessage(self, sender, text, metadata=None):
205         """Displays to the user a message sent to this group from the given sender
206         @type sender: string (XXX: Not Person?)
207         @type text: string
208         @type metadata: dict
209         """
210         self.pipe.add("<%s/%s> %s" % (sender, self.group.name, text))
211
212     def setGroupMembers(self, members):
213         """Sets the list of members in the group and displays it to the user
214         """
215         self.members = members
216         self.refreshMemberList()
217
218     def setTopic(self, topic, author):
219         """Displays the topic (from the server) for the group conversation window
220
221         @type topic: string
222         @type author: string (XXX: Not Person?)
223         """
224         self.pipe.add("-!- %s set the topic of %s to: %s" % (author, self.group.name, topic))
225 #        print "-!- %s set the topic of %s to: %s" % (author, self.group.name, topic)        
226
227     def serverMsg(self, message):
228         """Displays a serverMsg in the group conversation window
229
230         @type message: string
231         """
232         self.pipe.add("-!- %s " % (message))
233
234     def memberJoined(self, member):
235         """Adds the given member to the list of members in the group conversation
236         and displays this to the user
237
238         @type member: string (XXX: Not Person?)
239         """
240         if not member in self.members:
241             self.members.append(member)
242         self.pipe.add("-!- %s joined %s" % (member, self.group.name))
243         self.refreshMemberList()
244
245     def memberChangedNick(self, oldnick, newnick):
246         """Changes the oldnick in the list of members to newnick and displays this
247         change to the user
248
249         @type oldnick: string
250         @type newnick: string
251         """
252         if oldnick in self.members:
253             self.members.remove(oldnick)
254             self.members.append(newnick)
255             #self.chatui.contactChangedNick(oldnick, newnick)
256         self.pipe.add("-!- %s is now known as %s in %s" % (oldnick, newnick, self.group.name))
257         self.refreshMemberList()
258
259     def memberLeft(self, member):
260         """Deletes the given member from the list of members in the group
261         conversation and displays the change to the user
262
263         @type member: string
264         """
265         if member in self.members:
266             self.members.remove(member)
267         self.pipe.add("-!- %s left %s" % (member, self.group.name))
268         self.refreshMemberList()
269         
270         
271     def refreshMemberList(self):
272         self.pipe.clearBuddyList()
273         self.members.sort(lambda x,y: cmp(string.lower(x), string.lower(y)))
274         self.pipe.getCannelName(self.group.name)
275         for member in self.members:
276             self.pipe.buildBuddyList(str(member))
277 #        print "Channel : #%s" % self.group.name
278         print "Buddylist of #%s : \n%s" % (self.group.name, self.pipe.showBuddyList())
279 #        self.pipe.showBuddyList()
280 #        self.pipe.updateBuddyWindow(self.pipe.showBuddyList())
281         self.pipe.updateBuddyWindow()
282         
283 class ChatUI:
284     """A GUI chat client"""
285     def __init__(self):
286         self.conversations = {}      # cache of all direct windows
287         self.groupConversations = {} # cache of all group windows
288         self.persons = {}            # keys are (name, client)
289         self.groups = {}             # cache of all groups
290         self.onlineClients = []      # list of message sources currently online
291         self.contactsList = ContactsList(self)
292         self.pipe = MessagePipe()
293         self.helper = ""
294
295     def registerAccountClient(self, client):
296         """Notifies user that an account has been signed on to.
297
298         @type client: L{Client<interfaces.IClient>}
299         @returns: client, so that I may be used in a callback chain
300         """
301         print "signing onto", client.accountName
302         self.onlineClients.append(client)
303         self.contactsList.registerAccountClient(client)
304         self.helper=client
305         print " --- %s ---" % self.helper
306         self.pipe.add("signing onto %s" % client)
307         self.pipe.add("signing onto %s" % client.accountName)
308         return client
309
310     def unregisterAccountClient(self, client):
311         """Notifies user that an account has been signed off or disconnected
312
313         @type client: L{Client<interfaces.IClient>}
314         """
315         print "signing off from", client.accountName
316         self.onlineClients.remove(client)
317         self.contactsList.unregisterAccountClient(client)
318
319     def remClient(self):
320         """Notifies user that an account has been signed off or disconnected
321
322         @type client: L{Client<interfaces.IClient>}
323         """
324         print " --- %s ---" % self.helper
325         print "signing off from", self.helper.accountName
326         self.pipe.add("signing off %s" % helper)
327         self.pipe.add("signing off %s" % helper.accountName)        
328         self.onlineClients.remove(helper)
329         self.contactsList.unregisterAccountClient(helper)
330
331     def getContactsList(self):
332         """
333         @returntype: L{ContactsList}
334         """
335         print "contactlist = %s" % self.contactsList
336         return self.contactsList
337
338
339     def getConversation(self, person, Class=Conversation, stayHidden=0):
340         """For the given person object, returns the conversation window
341         or creates and returns a new conversation window if one does not exist.
342
343         @type person: L{Person<interfaces.IPerson>}
344         @type Class: L{Conversation<interfaces.IConversation>} class
345         @type stayHidden: boolean
346
347         @returntype: L{Conversation<interfaces.IConversation>}
348         """
349         conv = self.conversations.get(person)
350         if not conv:
351             conv = Class(person, self)
352             self.conversations[person] = conv
353         if stayHidden:
354             conv.hide()
355         else:
356             conv.show()
357         return conv
358
359     def getGroupConversation(self,group,Class=GroupConversation,stayHidden=0):
360         """For the given group object, returns the group conversation window or
361         creates and returns a new group conversation window if it doesn't exist
362
363         @type group: L{Group<interfaces.IGroup>}
364         @type Class: L{Conversation<interfaces.IConversation>} class
365         @type stayHidden: boolean
366
367         @returntype: L{GroupConversation<interfaces.IGroupConversation>}
368         """
369         conv = self.groupConversations.get(group)
370         if not conv:
371             conv = Class(group, self)
372             self.groupConversations[group] = conv
373         if stayHidden:
374             conv.hide()
375         else:
376             conv.show()
377 #        print "[dreamIRC] : " , conv
378         return conv
379
380     def getPerson(self, name, client):
381         """For the given name and account client, returns the instance of the
382         AbstractPerson subclass, or creates and returns a new AbstractPerson
383         subclass of the type Class
384
385         @type name: string
386         @type client: L{Client<interfaces.IClient>}
387
388         @returntype: L{Person<interfaces.IPerson>}
389         """
390         account = client.account
391         p = self.persons.get((name, account))
392         if not p:
393             p = account.getPerson(name)
394             self.persons[name, account] = p
395         return p
396
397     def getGroup(self, name, client):
398         """For the given name and account client, returns the instance of the
399         AbstractGroup subclass, or creates and returns a new AbstractGroup
400         subclass of the type Class
401
402         @type name: string
403         @type client: L{Client<interfaces.IClient>}
404
405         @returntype: L{Group<interfaces.IGroup>}
406         """
407         # I accept 'client' instead of 'account' in my signature for
408         # backwards compatibility.  (Groups changed to be Account-oriented
409         # in CVS revision 1.8.)
410         account = client.account
411         g = self.groups.get((name, account))
412         if not g:
413             g = account.getGroup(name)
414             self.groups[name, account] = g
415 #        self.pipe.add("joined %s" % g)
416         return g
417
418     def contactChangedNick(self, oldnick, newnick):
419         """For the given person, changes the person's name to newnick, and
420         tells the contact list and any conversation windows with that person
421         to change as well.
422
423         @type oldnick: string
424         @type newnick: string
425         """
426         if self.persons.has_key((person.name, person.account)):
427             conv = self.conversations.get(person)
428             if conv:
429                 conv.contactChangedNick(person, newnick)
430
431             self.contactsList.contactChangedNick(person, newnick)
432
433             del self.persons[person.name, person.account]
434             person.name = newnick
435             self.persons[person.name, person.account] = person
436
437     def sendOutPipe(self):
438         print "groupchat %s" % self.pipe.OutText
439         if len(self.pipe.OutText()) > 0:
440             self.sendText(self.pipe.OutText())
441             self.pipe.clearOutText()