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