1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 """Presence XMPP stanza handling
19
20 Normative reference:
21 - `RFC 3920 <http://www.ietf.org/rfc/rfc3920.txt>`__
22 """
23
24 __docformat__="restructuredtext en"
25
26 import libxml2
27
28 from pyxmpp.utils import to_utf8,from_utf8
29 from pyxmpp.stanza import Stanza
30 from pyxmpp.xmlextra import common_ns
31
32 presence_types=("available","unavailable","probe","subscribe","unsubscribe","subscribed",
33 "unsubscribed","invisible","error")
34
35 accept_responses={
36 "subscribe": "subscribed",
37 "subscribed": "subscribe",
38 "unsubscribe": "unsubscribed",
39 "unsubscribed": "unsubscribe",
40 }
41
42 deny_responses={
43 "subscribe": "unsubscribed",
44 "subscribed": "unsubscribe",
45 "unsubscribe": "subscribed",
46 "unsubscribed": "subscribe",
47 }
48
50 """Wraper object for <presence /> stanzas."""
51 stanza_type="presence"
52 - def __init__(self, xmlnode = None, from_jid = None, to_jid = None, stanza_type = None,
53 stanza_id = None, show = None, status = None, priority = 0,
54 error = None, error_cond = None, stream = None):
55 """Initialize a `Presence` object.
56
57 :Parameters:
58 - `xmlnode`: XML node to_jid be wrapped into the `Presence` object
59 or other Presence object to be copied. If not given then new
60 presence stanza is created using following parameters.
61 - `from_jid`: sender JID.
62 - `to_jid`: recipient JID.
63 - `stanza_type`: staza type: one of: None, "available", "unavailable",
64 "subscribe", "subscribed", "unsubscribe", "unsubscribed" or
65 "error". "available" is automaticaly changed to_jid None.
66 - `stanza_id`: stanza id -- value of stanza's "id" attribute
67 - `show`: "show" field of presence stanza. One of: None, "away",
68 "xa", "dnd", "chat".
69 - `status`: descriptive text for the presence stanza.
70 - `priority`: presence priority.
71 - `error_cond`: error condition name. Ignored if `stanza_type` is not "error"
72 :Types:
73 - `xmlnode`: `unicode` or `libxml2.xmlNode` or `Stanza`
74 - `from_jid`: `JID`
75 - `to_jid`: `JID`
76 - `stanza_type`: `unicode`
77 - `stanza_id`: `unicode`
78 - `show`: `unicode`
79 - `status`: `unicode`
80 - `priority`: `unicode`
81 - `error_cond`: `unicode`"""
82 self.xmlnode=None
83 if isinstance(xmlnode,Presence):
84 pass
85 elif isinstance(xmlnode,Stanza):
86 raise TypeError,"Couldn't make Presence from other Stanza"
87 elif isinstance(xmlnode,libxml2.xmlNode):
88 pass
89 elif xmlnode is not None:
90 raise TypeError,"Couldn't make Presence from %r" % (type(xmlnode),)
91
92 if stanza_type and stanza_type not in presence_types:
93 raise ValueError, "Invalid presence type: %r" % (type,)
94
95 if stanza_type=="available":
96 stanza_type=None
97
98 if xmlnode is None:
99 xmlnode="presence"
100
101 Stanza.__init__(self, xmlnode, from_jid = from_jid, to_jid = to_jid, stanza_type = stanza_type,
102 stanza_id = stanza_id, error = error, error_cond = error_cond, stream = stream)
103
104 if show:
105 self.xmlnode.newTextChild(common_ns,"show",to_utf8(show))
106 if status:
107 self.xmlnode.newTextChild(common_ns,"status",to_utf8(status))
108 if priority and priority!=0:
109 self.xmlnode.newTextChild(common_ns,"priority",to_utf8(unicode(priority)))
110
112 """Create a deep copy of the presence stanza.
113
114 :returntype: `Presence`"""
115 return Presence(self)
116
118 """Change presence status description.
119
120 :Parameters:
121 - `status`: descriptive text for the presence stanza.
122 :Types:
123 - `status`: `unicode`"""
124 n=self.xpath_eval("ns:status")
125 if not status:
126 if n:
127 n[0].unlinkNode()
128 n[0].freeNode()
129 else:
130 return
131 if n:
132 n[0].setContent(to_utf8(status))
133 else:
134 self.xmlnode.newTextChild(common_ns,"status",to_utf8(status))
135
137 """Get presence status description.
138
139 :return: value of stanza's <status/> field.
140 :returntype: `unicode`"""
141 n=self.xpath_eval("ns:status")
142 if n:
143 return from_utf8(n[0].getContent())
144 else:
145 return None
146
148 """Get presence "show" field.
149
150 :return: value of stanza's <show/> field.
151 :returntype: `unicode`"""
152 n=self.xpath_eval("ns:show")
153 if n:
154 return from_utf8(n[0].getContent())
155 else:
156 return None
157
159 """Change presence "show" field.
160
161 :Parameters:
162 - `show`: new value for the "show" field of presence stanza. One
163 of: None, "away", "xa", "dnd", "chat".
164 :Types:
165 - `show`: `unicode`"""
166 n=self.xpath_eval("ns:show")
167 if not show:
168 if n:
169 n[0].unlinkNode()
170 n[0].freeNode()
171 else:
172 return
173 if n:
174 n[0].setContent(to_utf8(show))
175 else:
176 self.xmlnode.newTextChild(common_ns,"show",to_utf8(show))
177
179 """Get presence priority.
180
181 :return: value of stanza's priority. 0 if the stanza doesn't contain
182 <priority/> element.
183 :returntype: `int`"""
184 n=self.xpath_eval("ns:priority")
185 if not n:
186 return 0
187 try:
188 prio=int(n[0].getContent())
189 except ValueError:
190 return 0
191 return prio
192
194 """Change presence priority.
195
196 :Parameters:
197 - `priority`: new presence priority.
198 :Types:
199 - `priority`: `int`"""
200 n=self.xpath_eval("ns:priority")
201 if not priority:
202 if n:
203 n[0].unlinkNode()
204 n[0].freeNode()
205 else:
206 return
207 priority=int(priority)
208 if priority<-128 or priority>127:
209 raise ValueError, "Bad priority value"
210 priority=str(priority)
211 if n:
212 n[0].setContent(priority)
213 else:
214 self.xmlnode.newTextChild(common_ns,"priority",priority)
215
217 """Create "accept" response for the "subscribe"/"subscribed"/"unsubscribe"/"unsubscribed"
218 presence stanza.
219
220 :return: new stanza.
221 :returntype: `Presence`"""
222
223 if self.get_type() not in ("subscribe","subscribed","unsubscribe","unsubscribed"):
224 raise ValueError, ("Results may only be generated for 'subscribe',"
225 "'subscribed','unsubscribe' or 'unsubscribed' presence")
226
227 pr=Presence(stanza_type=accept_responses[self.get_type()],
228 from_jid=self.get_to(),to_jid=self.get_from(),stanza_id=self.get_id())
229 return pr
230
232 """Create "deny" response for the "subscribe"/"subscribed"/"unsubscribe"/"unsubscribed"
233 presence stanza.
234
235 :return: new presence stanza.
236 :returntype: `Presence`"""
237 if self.get_type() not in ("subscribe","subscribed","unsubscribe","unsubscribed"):
238 raise ValueError, ("Results may only be generated for 'subscribe',"
239 "'subscribed','unsubscribe' or 'unsubscribed' presence")
240
241 pr=Presence(stanza_type=deny_responses[self.get_type()],
242 from_jid=self.get_to(),to_jid=self.get_from(),stanza_id=self.get_id())
243 return pr
244
246 """Create error response for the any non-error presence stanza.
247
248 :Parameters:
249 - `cond`: error condition name, as defined in XMPP specification.
250 :Types:
251 - `cond`: `unicode`
252
253 :return: new presence stanza.
254 :returntype: `Presence`"""
255
256 if self.get_type() == "error":
257 raise ValueError, "Errors may not be generated in response to errors"
258
259 p=Presence(stanza_type="error",from_jid=self.get_to(),to_jid=self.get_from(),
260 stanza_id=self.get_id(),error_cond=cond)
261
262 if self.xmlnode.children:
263 n=self.xmlnode.children
264 while n:
265 p.xmlnode.children.addPrevSibling(n.copyNode(1))
266 n=n.next
267 return p
268
269
270