]> code.delx.au - pymsnt/blob - src/contact.py
Groupchat timeout is configurable.
[pymsnt] / src / contact.py
1 # Copyright 2005 James Bunton <james@delx.cjb.net>
2 # Licensed for distribution under the GPL version 2, check COPYING for details
3
4 from debug import LogEvent, INFO, WARN, ERROR
5
6 from twisted.internet import reactor
7 from tlib.xmlw import Element
8
9 import disco
10 import legacy
11
12
13 class Contact:
14 """ Represents a Jabber contact """
15 def __init__(self, jid, sub, contactList):
16 self.jid = jid
17 self.contactList = contactList
18 self.groups = []
19 self.origsub = sub
20 self.sub = sub
21 self.nickname = ""
22 self.avatar = None
23 self.show = ""
24 self.status = ""
25 self.ptype = "unavailable"
26
27 def removeMe(self):
28 """ Destroys this object. Does not remove the contact from the server's list. """
29 self.contactList = None
30 self.avatar = None
31
32 def syncContactGrantedAuth(self):
33 """ Since last using the transport the user has been granted authorisation by this contact.
34 Call this to synchronise the user's Jabber list with their legacy list after logon. """
35 if self.sub == "none":
36 self.sub = "to"
37 elif self.sub == "from":
38 self.sub = "both"
39 else:
40 return
41
42 def syncContactRemovedAuth(self):
43 """ Since last using the transport the user has been blocked by this contact.
44 Call this to synchronise the user's Jabber list with their legacy list after logon. """
45 if self.sub == "to":
46 self.sub = "none"
47 elif self.sub == "both":
48 self.sub = "from"
49 else:
50 return
51
52 def syncUserGrantedAuth(self):
53 """ Since last using the transport the user has granted authorisation to this contact.
54 Call this to synchronise the user's Jabber list with their legacy list after logon. """
55 if self.sub == "none":
56 self.sub = "from"
57 elif self.sub == "to":
58 self.sub = "both"
59 else:
60 return
61
62 def syncUserRemovedAuth(self):
63 """ Since last using the transport the user has removed this contact's authorisation.
64 Call this to synchronise the user's Jabber list with their legacy list after logon. """
65 if self.sub == "from":
66 self.sub = "none"
67 elif self.sub == "both":
68 self.sub = "to"
69 else:
70 return
71
72 def syncGroups(self, groups, push=True):
73 """ Set the groups that this contact is in on the legacy service.
74 By default this pushes the groups out with a presence subscribed packet. """
75 self.groups = groups
76 if push: self.syncRoster(ptype="subscribed");
77
78 syncChoice = {
79 ("none", "none") : "", #
80 ("none", "to" ) : "subscribe", # User+ Contact
81 ("none", "from") : "subscribe", # User Contact+
82 ("none", "both") : "subscribe", # User+ Contact+
83 ("to" , "none") : "unsubscribed", # User- Contact
84 ("to" , "to" ) : "", #
85 ("to" , "from") : "unsubscribe", # User- Contact+ **
86 ("to" , "both") : "subscribe", # User Contact+
87 ("from", "none") : "unsubscribe", # User Contact-
88 ("from", "to" ) : "subscribe", # User+ Contact- *
89 ("from", "from") : "", #
90 ("from", "both") : "subscribe", # User+ Contact
91 ("both", "none") : "unsubscribed", # User- Contact- *
92 ("both", "to" ) : "unsubscribe", # User Contact-
93 ("both", "from") : "unsubscribed", # User- Contact
94 ("both", "both") : "" #
95 }
96
97 def syncRoster(self, ptype=""):
98 if not ptype:
99 ptype = self.syncChoice.get((self.origsub, self.sub))
100 if ptype:
101 self.contactList.session.sendRosterImport(jid=self.jid, ptype=ptype, sub=self.sub, groups=self.groups, name=self.nickname)
102
103 def contactGrantsAuth(self):
104 """ Live roster event """
105 if self.sub == "none":
106 self.sub = "to"
107 elif self.sub == "from":
108 self.sub = "both"
109 self.sendSub("subscribed")
110 self.sendPresence()
111
112 def contactRemovesAuth(self):
113 """ Live roster event """
114 if self.sub == "to":
115 self.sub = "none"
116 elif self.sub == "both":
117 self.sub = "from"
118 self.sendSub("unsubscribed")
119
120 def contactRequestsAuth(self):
121 """ Live roster event """
122 self.sendSub("subscribe")
123
124 def contactDerequestsAuth(self):
125 """ Live roster event """
126 self.sendSub("unsubscribe")
127
128 def jabberSubscriptionReceived(self, subtype):
129 """ Updates the subscription state internally and pushes the update to the legacy server """
130 if subtype == "subscribe":
131 if self.sub == "to" or self.sub == "both":
132 self.sendSub("subscribed")
133 else:
134 self.contactList.legacyList.addContact(self.jid)
135
136 elif subtype == "subscribed":
137 if self.sub == "none":
138 self.sub = "from"
139 if self.sub == "to":
140 self.sub = "both"
141 self.contactList.legacyList.authContact(self.jid)
142
143 elif subtype == "unsubscribe":
144 if self.sub == "none" or self.sub == "from":
145 self.sendSub("unsubscribed")
146 if self.sub == "both":
147 self.sub = "from"
148 if self.sub == "to":
149 self.sub = "none"
150 self.contactList.legacyList.removeContact(self.jid)
151
152 elif subtype == "unsubscribed":
153 if self.sub == "both":
154 self.sub = "to"
155 if self.sub == "from":
156 self.sub = "none"
157 self.contactList.legacyList.deauthContact(self.jid)
158
159 def updateNickname(self, nickname, push=True):
160 if self.nickname != nickname:
161 self.nickname = nickname
162 if push: self.sendPresence()
163
164 def updatePresence(self, show, status, ptype, force=False):
165 updateFlag = (self.show != show or self.status != status or self.ptype != ptype or force)
166 self.show = show
167 self.status = status
168 self.ptype = ptype
169 if updateFlag:
170 self.sendPresence()
171
172 def updateAvatar(self, avatar=None, push=True):
173 if self.avatar == avatar:
174 return
175 self.avatar = avatar
176 if push:
177 self.sendPresence()
178
179 def sendSub(self, ptype):
180 self.contactList.session.sendPresence(to=self.contactList.session.jabberID, fro=self.jid + "/" + legacy.id, ptype=ptype)
181
182 def sendPresence(self, tojid=""):
183 avatarHash = ""
184 if self.avatar:
185 avatarHash = self.avatar.getImageHash()
186 caps = Element((None, "c"))
187 caps.attributes["xmlns"] = disco.CAPS
188 caps.attributes["node"] = legacy.url + "/protocol/caps"
189 caps.attributes["ver"] = legacy.version
190 if not tojid:
191 tojid=self.contactList.session.jabberID
192 self.contactList.session.sendPresence(to=tojid, fro=self.jid + "/" + legacy.id, ptype=self.ptype, show=self.show, status=self.status, avatarHash=avatarHash, nickname=self.nickname, payload=[caps])
193
194
195
196 class ContactList:
197 """ Represents the Jabber contact list """
198 def __init__(self, session):
199 LogEvent(INFO, session.jabberID)
200 self.session = session
201 self.contacts = {}
202
203 def removeMe(self):
204 """ Cleanly removes the object """
205 LogEvent(INFO, self.session.jabberID)
206 for jid in self.contacts:
207 self.contacts[jid].updatePresence("", "", "unavailable")
208 self.contacts[jid].removeMe()
209 self.contacts = {}
210 self.session = None
211 self.legacyList = None
212
213 def resendLists(self, tojid=""):
214 for jid in self.contacts:
215 if self.contacts[jid].ptype != "unavailable" :
216 self.contacts[jid].sendPresence(tojid)
217 LogEvent(INFO, self.session.jabberID)
218
219 def createContact(self, jid, sub):
220 """ Creates a contact object. Use this to initialise the contact list
221 Returns a Contact object which you can call sync* methods on to synchronise
222 the user's legacy contact list with their Jabber list """
223 LogEvent(INFO, self.session.jabberID)
224 c = Contact(jid, sub, self)
225 self.contacts[jid] = c
226 return c
227
228 def getContact(self, jid):
229 """ Finds the contact. If one doesn't exist then a new one is created, with sub set to "none" """
230 if not self.contacts.has_key(jid):
231 self.contacts[jid] = Contact(jid, "none", self)
232 return self.contacts[jid]
233
234 def findContact(self, jid):
235 if self.contacts.has_key(jid):
236 return self.contacts[jid]
237 return None
238
239 def jabberSubscriptionReceived(self, jid, subtype):
240 self.getContact(jid).jabberSubscriptionReceived(subtype)
241
242