1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """
18 Protocol module contains tools that are needed for processing of xmpp-related
19 data structures, including jabber-objects like JID or different stanzas and
20 sub- stanzas) handling routines
21 """
22
23 from simplexml import Node, NodeBuilder
24 import time
25 import string
26 import hashlib
27
29 trans_table = string.maketrans(string.ascii_lowercase,
30 string.ascii_uppercase)
31 return s.translate(trans_table)
32
33 NS_ACTIVITY = 'http://jabber.org/protocol/activity'
34 NS_ADDRESS = 'http://jabber.org/protocol/address'
35 NS_AGENTS = 'jabber:iq:agents'
36 NS_AMP = 'http://jabber.org/protocol/amp'
37 NS_AMP_ERRORS = NS_AMP + '#errors'
38 NS_ARCHIVE = 'urn:xmpp:archive'
39 NS_ARCHIVE_AUTO = NS_ARCHIVE + ':auto'
40 NS_ARCHIVE_MANAGE = NS_ARCHIVE + ':manage'
41 NS_ARCHIVE_MANUAL = NS_ARCHIVE + ':manual'
42 NS_ARCHIVE_PREF = NS_ARCHIVE + ':pref'
43 NS_ATOM = 'http://www.w3.org/2005/Atom'
44 NS_ATTENTION = 'urn:xmpp:attention:0'
45 NS_AUTH = 'jabber:iq:auth'
46 NS_AVATAR = 'http://www.xmpp.org/extensions/xep-0084.html#ns-metadata'
47 NS_BIND = 'urn:ietf:params:xml:ns:xmpp-bind'
48 NS_BLOCKING = 'urn:xmpp:blocking'
49 NS_BOB = 'urn:xmpp:bob'
50 NS_BOOKMARKS = 'storage:bookmarks'
51 NS_BROWSE = 'jabber:iq:browse'
52 NS_BROWSING = 'http://jabber.org/protocol/browsing'
53 NS_BYTESTREAM = 'http://jabber.org/protocol/bytestreams'
54 NS_CAPS = 'http://jabber.org/protocol/caps'
55 NS_CAPTCHA = 'urn:xmpp:captcha'
56 NS_CARBONS = 'urn:xmpp:carbons:2'
57 NS_CHATSTATES = 'http://jabber.org/protocol/chatstates'
58 NS_CHATTING = 'http://jabber.org/protocol/chatting'
59 NS_CLIENT = 'jabber:client'
60 NS_CONDITIONS = 'urn:xmpp:muc:conditions:0'
61 NS_COMMANDS = 'http://jabber.org/protocol/commands'
62 NS_COMPONENT_ACCEPT = 'jabber:component:accept'
63 NS_COMPONENT_1 = 'http://jabberd.jabberstudio.org/ns/component/1.0'
64 NS_COMPRESS = 'http://jabber.org/protocol/compress'
65 NS_CONFERENCE = 'jabber:x:conference'
66 NS_CORRECT = 'urn:xmpp:message-correct:0'
67 NS_DATA = 'jabber:x:data'
68 NS_DATA_MEDIA = 'urn:xmpp:media-element'
69 NS_DELAY = 'jabber:x:delay'
70 NS_DELAY2 = 'urn:xmpp:delay'
71 NS_DIALBACK = 'jabber:server:dialback'
72 NS_DISCO = 'http://jabber.org/protocol/disco'
73 NS_DISCO_INFO = NS_DISCO + '#info'
74 NS_DISCO_ITEMS = NS_DISCO + '#items'
75 NS_ENCRYPTED = 'jabber:x:encrypted'
76 NS_ESESSION = 'http://www.xmpp.org/extensions/xep-0116.html#ns'
77 NS_ESESSION_INIT = 'http://www.xmpp.org/extensions/xep-0116.html#ns-init'
78 NS_EVENT = 'jabber:x:event'
79 NS_FEATURE = 'http://jabber.org/protocol/feature-neg'
80 NS_FILE = 'http://jabber.org/protocol/si/profile/file-transfer'
81 NS_FORWARD = 'urn:xmpp:forward:0'
82 NS_GAMING = 'http://jabber.org/protocol/gaming'
83 NS_GATEWAY = 'jabber:iq:gateway'
84 NS_GEOLOC = 'http://jabber.org/protocol/geoloc'
85 NS_GROUPCHAT = 'gc-1.0'
86 NS_HTTP_AUTH = 'http://jabber.org/protocol/http-auth'
87 NS_HTTP_BIND = 'http://jabber.org/protocol/httpbind'
88 NS_IBB = 'http://jabber.org/protocol/ibb'
89 NS_INVISIBLE = 'presence-invisible'
90 NS_IQ = 'iq'
91 NS_JINGLE ='urn:xmpp:jingle:1'
92 NS_JINGLE_ERRORS = 'urn:xmpp:jingle:errors:1'
93 NS_JINGLE_RTP = 'urn:xmpp:jingle:apps:rtp:1'
94 NS_JINGLE_RTP_AUDIO = 'urn:xmpp:jingle:apps:rtp:audio'
95 NS_JINGLE_RTP_VIDEO = 'urn:xmpp:jingle:apps:rtp:video'
96 NS_JINGLE_FILE_TRANSFER ='urn:xmpp:jingle:apps:file-transfer:3'
97 NS_JINGLE_XTLS='urn:xmpp:jingle:security:xtls:0'
98 NS_JINGLE_RAW_UDP = 'urn:xmpp:jingle:transports:raw-udp:1'
99 NS_JINGLE_ICE_UDP = 'urn:xmpp:jingle:transports:ice-udp:1'
100 NS_JINGLE_BYTESTREAM ='urn:xmpp:jingle:transports:s5b:1'
101 NS_JINGLE_IBB = 'urn:xmpp:jingle:transports:ibb:1'
102 NS_LAST = 'jabber:iq:last'
103 NS_LOCATION = 'http://jabber.org/protocol/geoloc'
104 NS_MAM = 'urn:xmpp:mam:tmp'
105 NS_MESSAGE = 'message'
106 NS_MOOD = 'http://jabber.org/protocol/mood'
107 NS_MUC = 'http://jabber.org/protocol/muc'
108 NS_MUC_USER = NS_MUC + '#user'
109 NS_MUC_ADMIN = NS_MUC + '#admin'
110 NS_MUC_OWNER = NS_MUC + '#owner'
111 NS_MUC_UNIQUE = NS_MUC + '#unique'
112 NS_MUC_CONFIG = NS_MUC + '#roomconfig'
113 NS_NICK = 'http://jabber.org/protocol/nick'
114 NS_OFFLINE = 'http://www.jabber.org/jeps/jep-0030.html'
115 NS_PHYSLOC = 'http://jabber.org/protocol/physloc'
116 NS_PING = 'urn:xmpp:ping'
117 NS_PRESENCE = 'presence'
118 NS_PRIVACY = 'jabber:iq:privacy'
119 NS_PRIVATE = 'jabber:iq:private'
120 NS_PROFILE = 'http://jabber.org/protocol/profile'
121 NS_PUBSUB = 'http://jabber.org/protocol/pubsub'
122 NS_PUBSUB_EVENT = 'http://jabber.org/protocol/pubsub#event'
123 NS_PUBSUB_PUBLISH_OPTIONS = NS_PUBSUB + '#publish-options'
124 NS_PUBSUB_OWNER = 'http://jabber.org/protocol/pubsub#owner'
125 NS_REGISTER = 'jabber:iq:register'
126 NS_ROSTER = 'jabber:iq:roster'
127 NS_ROSTERNOTES = 'storage:rosternotes'
128 NS_ROSTERX = 'http://jabber.org/protocol/rosterx'
129 NS_ROSTER_VER = 'urn:xmpp:features:rosterver'
130 NS_RPC = 'jabber:iq:rpc'
131 NS_RSM = 'http://jabber.org/protocol/rsm'
132 NS_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl'
133 NS_SECLABEL = 'urn:xmpp:sec-label:0'
134 NS_SECLABEL_CATALOG = 'urn:xmpp:sec-label:catalog:2'
135 NS_SEARCH = 'jabber:iq:search'
136 NS_SERVER = 'jabber:server'
137 NS_SESSION = 'urn:ietf:params:xml:ns:xmpp-session'
138 NS_SI = 'http://jabber.org/protocol/si'
139 NS_SI_PUB = 'http://jabber.org/protocol/sipub'
140 NS_SIGNED = 'jabber:x:signed'
141 NS_SSN = 'urn:xmpp:ssn'
142 NS_STANZA_CRYPTO = 'http://www.xmpp.org/extensions/xep-0200.html#ns'
143 NS_STANZAS = 'urn:ietf:params:xml:ns:xmpp-stanzas'
144 NS_STREAM = 'http://affinix.com/jabber/stream'
145 NS_STREAMS = 'http://etherx.jabber.org/streams'
146 NS_TIME = 'jabber:iq:time'
147 NS_TIME_REVISED = 'urn:xmpp:time'
148 NS_TLS = 'urn:ietf:params:xml:ns:xmpp-tls'
149 NS_TUNE = 'http://jabber.org/protocol/tune'
150 NS_VACATION = 'http://jabber.org/protocol/vacation'
151 NS_VCARD = 'vcard-temp'
152 NS_GMAILNOTIFY = 'google:mail:notify'
153 NS_GTALKSETTING = 'google:setting'
154 NS_VCARD_UPDATE = NS_VCARD + ':x:update'
155 NS_VERSION = 'jabber:iq:version'
156 NS_VIEWING = 'http://jabber.org/protocol/viewing'
157 NS_WAITINGLIST = 'http://jabber.org/protocol/waitinglist'
158 NS_XHTML_IM = 'http://jabber.org/protocol/xhtml-im'
159 NS_XHTML = 'http://www.w3.org/1999/xhtml'
160 NS_X_OOB = 'jabber:x:oob'
161 NS_DATA_LAYOUT = 'http://jabber.org/protocol/xdata-layout'
162 NS_DATA_VALIDATE = 'http://jabber.org/protocol/xdata-validate'
163 NS_XMPP_STREAMS = 'urn:ietf:params:xml:ns:xmpp-streams'
164 NS_RECEIPTS = 'urn:xmpp:receipts'
165 NS_PUBKEY_PUBKEY = 'urn:xmpp:pubkey:2'
166 NS_PUBKEY_REVOKE = 'urn:xmpp:revoke:2'
167 NS_PUBKEY_ATTEST = 'urn:xmpp:attest:2'
168 NS_STREAM_MGMT = 'urn:xmpp:sm:2'
169 NS_HASHES = 'urn:xmpp:hashes:1'
170 NS_HASHES_MD5 = 'urn:xmpp:hash-function-textual-names:md5'
171 NS_HASHES_SHA1 = 'urn:xmpp:hash-function-textual-names:sha-1'
172 NS_HASHES_SHA256 = 'urn:xmpp:hash-function-textual-names:sha-256'
173 NS_HASHES_SHA512 = 'urn:xmpp:hash-function-textual-names:sha-512'
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253 ERRORS = {
254 'urn:ietf:params:xml:ns:xmpp-sasl aborted': ['',
255 '',
256 'The receiving entity acknowledges an <abort/> element sent by the initiating entity; sent in reply to the <abort/> element.'],
257 'urn:ietf:params:xml:ns:xmpp-sasl incorrect-encoding': ['',
258 '',
259 'The data provided by the initiating entity could not be processed because the [BASE64]Josefsson, S., The Base16, Base32, and Base64 Data Encodings, July 2003. encoding is incorrect (e.g., because the encoding does not adhere to the definition in Section 3 of [BASE64]Josefsson, S., The Base16, Base32, and Base64 Data Encodings, July 2003.); sent in reply to a <response/> element or an <auth/> element with initial response data.'],
260 'urn:ietf:params:xml:ns:xmpp-sasl invalid-authzid': ['',
261 '',
262 'The authzid provided by the initiating entity is invalid, either because it is incorrectly formatted or because the initiating entity does not have permissions to authorize that ID; sent in reply to a <response/> element or an <auth/> element with initial response data.'],
263 'urn:ietf:params:xml:ns:xmpp-sasl invalid-mechanism': ['',
264 '',
265 'The initiating entity did not provide a mechanism or requested a mechanism that is not supported by the receiving entity; sent in reply to an <auth/> element.'],
266 'urn:ietf:params:xml:ns:xmpp-sasl mechanism-too-weak': ['',
267 '',
268 'The mechanism requested by the initiating entity is weaker than server policy permits for that initiating entity; sent in reply to a <response/> element or an <auth/> element with initial response data.'],
269 'urn:ietf:params:xml:ns:xmpp-sasl not-authorized': ['',
270 '',
271 'The authentication failed because the initiating entity did not provide valid credentials (this includes but is not limited to the case of an unknown username); sent in reply to a <response/> element or an <auth/> element with initial response data.'],
272 'urn:ietf:params:xml:ns:xmpp-sasl temporary-auth-failure': ['',
273 '',
274 'The authentication failed because of a temporary error condition within the receiving entity; sent in reply to an <auth/> element or <response/> element.'],
275 'urn:ietf:params:xml:ns:xmpp-stanzas bad-request': ['400',
276 'modify',
277 'The sender has sent XML that is malformed or that cannot be processed.'],
278 'urn:ietf:params:xml:ns:xmpp-stanzas conflict': ['409',
279 'cancel',
280 'Access cannot be granted because an existing resource or session exists with the same name or address.'],
281 'urn:ietf:params:xml:ns:xmpp-stanzas feature-not-implemented': ['501',
282 'cancel',
283 'The feature requested is not implemented by the recipient or server and therefore cannot be processed.'],
284 'urn:ietf:params:xml:ns:xmpp-stanzas forbidden': ['403',
285 'auth',
286 'The requesting entity does not possess the required permissions to perform the action.'],
287 'urn:ietf:params:xml:ns:xmpp-stanzas gone': ['302',
288 'modify',
289 'The recipient or server can no longer be contacted at this address.'],
290 'urn:ietf:params:xml:ns:xmpp-stanzas internal-server-error': ['500',
291 'wait',
292 'The server could not process the stanza because of a misconfiguration or an otherwise-undefined internal server error.'],
293 'urn:ietf:params:xml:ns:xmpp-stanzas item-not-found': ['404',
294 'cancel',
295 'The addressed JID or item requested cannot be found.'],
296 'urn:ietf:params:xml:ns:xmpp-stanzas jid-malformed': ['400',
297 'modify',
298 "The value of the 'to' attribute in the sender's stanza does not adhere to the syntax defined in Addressing Scheme."],
299 'urn:ietf:params:xml:ns:xmpp-stanzas not-acceptable': ['406',
300 'cancel',
301 'The recipient or server understands the request but is refusing to process it because it does not meet criteria defined by the recipient or server.'],
302 'urn:ietf:params:xml:ns:xmpp-stanzas not-allowed': ['405',
303 'cancel',
304 'The recipient or server does not allow any entity to perform the action.'],
305 'urn:ietf:params:xml:ns:xmpp-stanzas not-authorized': ['401',
306 'auth',
307 'The sender must provide proper credentials before being allowed to perform the action, or has provided improper credentials.'],
308 'urn:ietf:params:xml:ns:xmpp-stanzas payment-required': ['402',
309 'auth',
310 'The requesting entity is not authorized to access the requested service because payment is required.'],
311 'urn:ietf:params:xml:ns:xmpp-stanzas recipient-unavailable': ['404',
312 'wait',
313 'The intended recipient is temporarily unavailable.'],
314 'urn:ietf:params:xml:ns:xmpp-stanzas redirect': ['302',
315 'modify',
316 'The recipient or server is redirecting requests for this information to another entity.'],
317 'urn:ietf:params:xml:ns:xmpp-stanzas registration-required': ['407',
318 'auth',
319 'The requesting entity is not authorized to access the requested service because registration is required.'],
320 'urn:ietf:params:xml:ns:xmpp-stanzas remote-server-not-found': ['404',
321 'cancel',
322 'A remote server or service specified as part or all of the JID of the intended recipient does not exist.'],
323 'urn:ietf:params:xml:ns:xmpp-stanzas remote-server-timeout': ['504',
324 'wait',
325 'A remote server or service specified as part or all of the JID of the intended recipient could not be contacted within a reasonable amount of time.'],
326 'urn:ietf:params:xml:ns:xmpp-stanzas resource-constraint': ['500',
327 'wait',
328 'The server or recipient lacks the system resources necessary to service the request.'],
329 'urn:ietf:params:xml:ns:xmpp-stanzas service-unavailable': ['503',
330 'cancel',
331 'The server or recipient does not currently provide the requested service.'],
332 'urn:ietf:params:xml:ns:xmpp-stanzas subscription-required': ['407',
333 'auth',
334 'The requesting entity is not authorized to access the requested service because a subscription is required.'],
335 'urn:ietf:params:xml:ns:xmpp-stanzas undefined-condition': ['500',
336 '',
337 'Undefined Condition'],
338 'urn:ietf:params:xml:ns:xmpp-stanzas unexpected-request': ['400',
339 'wait',
340 'The recipient or server understood the request but was not expecting it at this time (e.g., the request was out of order).'],
341 'urn:ietf:params:xml:ns:xmpp-streams bad-format': ['',
342 '',
343 'The entity has sent XML that cannot be processed.'],
344 'urn:ietf:params:xml:ns:xmpp-streams bad-namespace-prefix': ['',
345 '',
346 'The entity has sent a namespace prefix that is unsupported, or has sent no namespace prefix on an element that requires such a prefix.'],
347 'urn:ietf:params:xml:ns:xmpp-streams conflict': ['',
348 '',
349 'The server is closing the active stream for this entity because a new stream has been initiated that conflicts with the existing stream.'],
350 'urn:ietf:params:xml:ns:xmpp-streams connection-timeout': ['',
351 '',
352 'The entity has not generated any traffic over the stream for some period of time.'],
353 'urn:ietf:params:xml:ns:xmpp-streams host-gone': ['',
354 '',
355 "The value of the 'to' attribute provided by the initiating entity in the stream header corresponds to a hostname that is no longer hosted by the server."],
356 'urn:ietf:params:xml:ns:xmpp-streams host-unknown': ['',
357 '',
358 "The value of the 'to' attribute provided by the initiating entity in the stream header does not correspond to a hostname that is hosted by the server."],
359 'urn:ietf:params:xml:ns:xmpp-streams improper-addressing': ['',
360 '',
361 "A stanza sent between two servers lacks a 'to' or 'from' attribute (or the attribute has no value)."],
362 'urn:ietf:params:xml:ns:xmpp-streams internal-server-error': ['',
363 '',
364 'The server has experienced a misconfiguration or an otherwise-undefined internal error that prevents it from servicing the stream.'],
365 'urn:ietf:params:xml:ns:xmpp-streams invalid-from': ['cancel',
366 '',
367 "The JID or hostname provided in a 'from' address does not match an authorized JID or validated domain negotiated between servers via SASL or dialback, or between a client and a server via authentication and resource authorization."],
368 'urn:ietf:params:xml:ns:xmpp-streams invalid-id': ['',
369 '',
370 'The stream ID or dialback ID is invalid or does not match an ID previously provided.'],
371 'urn:ietf:params:xml:ns:xmpp-streams invalid-namespace': ['',
372 '',
373 'The streams namespace name is something other than "http://etherx.jabber.org/streams" or the dialback namespace name is something other than "jabber:server:dialback".'],
374 'urn:ietf:params:xml:ns:xmpp-streams invalid-xml': ['',
375 '',
376 'The entity has sent invalid XML over the stream to a server that performs validation.'],
377 'urn:ietf:params:xml:ns:xmpp-streams not-authorized': ['',
378 '',
379 'The entity has attempted to send data before the stream has been authenticated, or otherwise is not authorized to perform an action related to stream negotiation.'],
380 'urn:ietf:params:xml:ns:xmpp-streams policy-violation': ['',
381 '',
382 'The entity has violated some local service policy.'],
383 'urn:ietf:params:xml:ns:xmpp-streams remote-connection-failed': ['',
384 '',
385 'The server is unable to properly connect to a remote resource that is required for authentication or authorization.'],
386 'urn:ietf:params:xml:ns:xmpp-streams resource-constraint': ['',
387 '',
388 'The server lacks the system resources necessary to service the stream.'],
389 'urn:ietf:params:xml:ns:xmpp-streams restricted-xml': ['',
390 '',
391 'The entity has attempted to send restricted XML features such as a comment, processing instruction, DTD, entity reference, or unescaped character.'],
392 'urn:ietf:params:xml:ns:xmpp-streams see-other-host': ['',
393 '',
394 'The server will not provide service to the initiating entity but is redirecting traffic to another host.'],
395 'urn:ietf:params:xml:ns:xmpp-streams system-shutdown': ['',
396 '',
397 'The server is being shut down and all active streams are being closed.'],
398 'urn:ietf:params:xml:ns:xmpp-streams undefined-condition': ['',
399 '',
400 'The error condition is not one of those defined by the other conditions in this list.'],
401 'urn:ietf:params:xml:ns:xmpp-streams unsupported-encoding': ['',
402 '',
403 'The initiating entity has encoded the stream in an encoding that is not supported by the server.'],
404 'urn:ietf:params:xml:ns:xmpp-streams unsupported-stanza-type': ['',
405 '',
406 'The initiating entity has sent a first-level child of the stream that is not supported by the server.'],
407 'urn:ietf:params:xml:ns:xmpp-streams unsupported-version': ['',
408 '',
409 "The value of the 'version' attribute provided by the initiating entity in the stream header specifies a version of XMPP that is not supported by the server."],
410 'urn:ietf:params:xml:ns:xmpp-streams xml-not-well-formed': ['',
411 '',
412 'The initiating entity has sent XML that is not well-formed.']
413 }
414
415 _errorcodes = {
416 '302': 'redirect',
417 '400': 'unexpected-request',
418 '401': 'not-authorized',
419 '402': 'payment-required',
420 '403': 'forbidden',
421 '404': 'remote-server-not-found',
422 '405': 'not-allowed',
423 '406': 'not-acceptable',
424 '407': 'subscription-required',
425 '409': 'conflict',
426 '500': 'undefined-condition',
427 '501': 'feature-not-implemented',
428 '503': 'service-unavailable',
429 '504': 'remote-server-timeout',
430 'cancel': 'invalid-from'
431 }
432
433 STREAM_NOT_AUTHORIZED = 'urn:ietf:params:xml:ns:xmpp-streams not-authorized'
434 STREAM_REMOTE_CONNECTION_FAILED = 'urn:ietf:params:xml:ns:xmpp-streams remote-connection-failed'
435 SASL_MECHANISM_TOO_WEAK = 'urn:ietf:params:xml:ns:xmpp-sasl mechanism-too-weak'
436 STREAM_XML_NOT_WELL_FORMED = 'urn:ietf:params:xml:ns:xmpp-streams xml-not-well-formed'
437 ERR_JID_MALFORMED = 'urn:ietf:params:xml:ns:xmpp-stanzas jid-malformed'
438 STREAM_SEE_OTHER_HOST = 'urn:ietf:params:xml:ns:xmpp-streams see-other-host'
439 STREAM_BAD_NAMESPACE_PREFIX = 'urn:ietf:params:xml:ns:xmpp-streams bad-namespace-prefix'
440 ERR_SERVICE_UNAVAILABLE = 'urn:ietf:params:xml:ns:xmpp-stanzas service-unavailable'
441 STREAM_CONNECTION_TIMEOUT = 'urn:ietf:params:xml:ns:xmpp-streams connection-timeout'
442 STREAM_UNSUPPORTED_VERSION = 'urn:ietf:params:xml:ns:xmpp-streams unsupported-version'
443 STREAM_IMPROPER_ADDRESSING = 'urn:ietf:params:xml:ns:xmpp-streams improper-addressing'
444 STREAM_UNDEFINED_CONDITION = 'urn:ietf:params:xml:ns:xmpp-streams undefined-condition'
445 SASL_NOT_AUTHORIZED = 'urn:ietf:params:xml:ns:xmpp-sasl not-authorized'
446 ERR_GONE = 'urn:ietf:params:xml:ns:xmpp-stanzas gone'
447 SASL_TEMPORARY_AUTH_FAILURE = 'urn:ietf:params:xml:ns:xmpp-sasl temporary-auth-failure'
448 ERR_REMOTE_SERVER_NOT_FOUND = 'urn:ietf:params:xml:ns:xmpp-stanzas remote-server-not-found'
449 ERR_UNEXPECTED_REQUEST = 'urn:ietf:params:xml:ns:xmpp-stanzas unexpected-request'
450 ERR_RECIPIENT_UNAVAILABLE = 'urn:ietf:params:xml:ns:xmpp-stanzas recipient-unavailable'
451 ERR_CONFLICT = 'urn:ietf:params:xml:ns:xmpp-stanzas conflict'
452 STREAM_SYSTEM_SHUTDOWN = 'urn:ietf:params:xml:ns:xmpp-streams system-shutdown'
453 STREAM_BAD_FORMAT = 'urn:ietf:params:xml:ns:xmpp-streams bad-format'
454 ERR_SUBSCRIPTION_REQUIRED = 'urn:ietf:params:xml:ns:xmpp-stanzas subscription-required'
455 STREAM_INTERNAL_SERVER_ERROR = 'urn:ietf:params:xml:ns:xmpp-streams internal-server-error'
456 ERR_NOT_AUTHORIZED = 'urn:ietf:params:xml:ns:xmpp-stanzas not-authorized'
457 SASL_ABORTED = 'urn:ietf:params:xml:ns:xmpp-sasl aborted'
458 ERR_REGISTRATION_REQUIRED = 'urn:ietf:params:xml:ns:xmpp-stanzas registration-required'
459 ERR_INTERNAL_SERVER_ERROR = 'urn:ietf:params:xml:ns:xmpp-stanzas internal-server-error'
460 SASL_INCORRECT_ENCODING = 'urn:ietf:params:xml:ns:xmpp-sasl incorrect-encoding'
461 STREAM_HOST_GONE = 'urn:ietf:params:xml:ns:xmpp-streams host-gone'
462 STREAM_POLICY_VIOLATION = 'urn:ietf:params:xml:ns:xmpp-streams policy-violation'
463 STREAM_INVALID_XML = 'urn:ietf:params:xml:ns:xmpp-streams invalid-xml'
464 STREAM_CONFLICT = 'urn:ietf:params:xml:ns:xmpp-streams conflict'
465 STREAM_RESOURCE_CONSTRAINT = 'urn:ietf:params:xml:ns:xmpp-streams resource-constraint'
466 STREAM_UNSUPPORTED_ENCODING = 'urn:ietf:params:xml:ns:xmpp-streams unsupported-encoding'
467 ERR_NOT_ALLOWED = 'urn:ietf:params:xml:ns:xmpp-stanzas not-allowed'
468 ERR_ITEM_NOT_FOUND = 'urn:ietf:params:xml:ns:xmpp-stanzas item-not-found'
469 ERR_NOT_ACCEPTABLE = 'urn:ietf:params:xml:ns:xmpp-stanzas not-acceptable'
470 STREAM_INVALID_FROM = 'urn:ietf:params:xml:ns:xmpp-streams invalid-from'
471 ERR_FEATURE_NOT_IMPLEMENTED = 'urn:ietf:params:xml:ns:xmpp-stanzas feature-not-implemented'
472 ERR_BAD_REQUEST = 'urn:ietf:params:xml:ns:xmpp-stanzas bad-request'
473 STREAM_INVALID_ID = 'urn:ietf:params:xml:ns:xmpp-streams invalid-id'
474 STREAM_HOST_UNKNOWN = 'urn:ietf:params:xml:ns:xmpp-streams host-unknown'
475 ERR_UNDEFINED_CONDITION = 'urn:ietf:params:xml:ns:xmpp-stanzas undefined-condition'
476 SASL_INVALID_MECHANISM = 'urn:ietf:params:xml:ns:xmpp-sasl invalid-mechanism'
477 STREAM_RESTRICTED_XML = 'urn:ietf:params:xml:ns:xmpp-streams restricted-xml'
478 ERR_RESOURCE_CONSTRAINT = 'urn:ietf:params:xml:ns:xmpp-stanzas resource-constraint'
479 ERR_REMOTE_SERVER_TIMEOUT = 'urn:ietf:params:xml:ns:xmpp-stanzas remote-server-timeout'
480 SASL_INVALID_AUTHZID = 'urn:ietf:params:xml:ns:xmpp-sasl invalid-authzid'
481 ERR_PAYMENT_REQUIRED = 'urn:ietf:params:xml:ns:xmpp-stanzas payment-required'
482 STREAM_INVALID_NAMESPACE = 'urn:ietf:params:xml:ns:xmpp-streams invalid-namespace'
483 ERR_REDIRECT = 'urn:ietf:params:xml:ns:xmpp-stanzas redirect'
484 STREAM_UNSUPPORTED_STANZA_TYPE = 'urn:ietf:params:xml:ns:xmpp-streams unsupported-stanza-type'
485 ERR_FORBIDDEN = 'urn:ietf:params:xml:ns:xmpp-stanzas forbidden'
486
488 """
489 Return true if the node is a positive reply
490 """
491 return node and node.getType() == 'result'
492
494 """
495 Return true if the node is a negative reply
496 """
497 return node and node.getType() == 'error'
498
500 """
501 Exception that should be raised by handler when the handling should be
502 stopped
503 """
504 pass
505
507 """
508 Base exception class for stream errors
509 """
510 pass
511
514
517
520
523
526
529
532
535
538
541
544
547
550
553
556
559
562
565
568
571
574
577
580
583
584 stream_exceptions = {'bad-format': BadFormat,
585 'bad-namespace-prefix': BadNamespacePrefix,
586 'conflict': Conflict,
587 'connection-timeout': ConnectionTimeout,
588 'host-gone': HostGone,
589 'host-unknown': HostUnknown,
590 'improper-addressing': ImproperAddressing,
591 'internal-server-error': InternalServerError,
592 'invalid-from': InvalidFrom,
593 'invalid-id': InvalidID,
594 'invalid-namespace': InvalidNamespace,
595 'invalid-xml': InvalidXML,
596 'not-authorized': NotAuthorized,
597 'policy-violation': PolicyViolation,
598 'remote-connection-failed': RemoteConnectionFailed,
599 'resource-constraint': ResourceConstraint,
600 'restricted-xml': RestrictedXML,
601 'see-other-host': SeeOtherHost,
602 'system-shutdown': SystemShutdown,
603 'undefined-condition': UndefinedCondition,
604 'unsupported-encoding': UnsupportedEncoding,
605 'unsupported-stanza-type': UnsupportedStanzaType,
606 'unsupported-version': UnsupportedVersion,
607 'xml-not-well-formed': XMLNotWellFormed}
608
610 """
611 JID can be built from string, modified, compared, serialised into string
612 """
613
614 - def __init__(self, jid=None, node='', domain='', resource=''):
615 """
616 JID can be specified as string (jid argument) or as separate parts
617
618 Examples:
619 JID('node@domain/resource')
620 JID(node='node',domain='domain.org')
621 """
622 if not jid and not domain:
623 raise ValueError('JID must contain at least domain name')
624 elif type(jid) == type(self):
625 self.node, self.domain = jid.node, jid.domain
626 self.resource = jid.resource
627 elif domain:
628 self.node, self.domain, self.resource = node, domain, resource
629 else:
630 if jid.find('@') + 1:
631 self.node, jid = jid.split('@', 1)
632 else:
633 self.node = ''
634 if jid.find('/')+1:
635 self.domain, self.resource = jid.split('/', 1)
636 else:
637 self.domain, self.resource = jid, ''
638
640 """
641 Return the node part of the JID
642 """
643 return self.node
644
646 """
647 Set the node part of the JID to new value. Specify None to remove
648 the node part
649 """
650 self.node = node.lower()
651
652 - def getDomain(self):
653 """
654 Return the domain part of the JID
655 """
656 return self.domain
657
658 - def setDomain(self, domain):
659 """
660 Set the domain part of the JID to new value
661 """
662 self.domain = domain.lower()
663
665 """
666 Return the resource part of the JID
667 """
668 return self.resource
669
671 """
672 Set the resource part of the JID to new value. Specify None to remove the
673 resource part
674 """
675 self.resource = resource
676
678 """
679 Return the bare representation of JID. I.e. string value w/o resource
680 """
681 return self.__str__(0)
682
684 """
685 Compare the JID to another instance or to string for equality
686 """
687 try:
688 other = JID(other)
689 except ValueError:
690 return 0
691 return self.resource == other.resource and \
692 self.__str__(0) == other.__str__(0)
693
695 """
696 Compare the JID to another instance or to string for non-equality
697 """
698 return not self.__eq__(other)
699
701 """
702 Compare the node and domain parts of the JID's for equality
703 """
704 return self.__str__(0) == JID(other).__str__(0)
705
707 """
708 Serialise JID into string
709 """
710 if self.node:
711 jid = self.node + '@' + self.domain
712 else:
713 jid = self.domain
714 if wresource and self.resource:
715 return jid + '/' + self.resource
716 return jid
717
719 """
720 Produce hash of the JID, Allows to use JID objects as keys of the
721 dictionary
722 """
723 return hash(str(self))
724
725 -class BOSHBody(Node):
726 """
727 <body> tag that wraps usual XMPP stanzas in XMPP over BOSH
728 """
729
730 - def __init__(self, attrs={}, payload=[], node=None):
731 Node.__init__(self, tag='body', attrs=attrs, payload=payload, node=node)
732 self.setNamespace(NS_HTTP_BIND)
733
734
736 """
737 A "stanza" object class. Contains methods that are common for presences, iqs
738 and messages
739 """
740
741 - def __init__(self, name=None, to=None, typ=None, frm=None, attrs={},
742 payload=[], timestamp=None, xmlns=None, node=None):
743 """
744 Constructor, name is the name of the stanza
745 i.e. 'message' or 'presence'or 'iq'
746
747 to is the value of 'to' attribure, 'typ' - 'type' attribute
748 frn - from attribure, attrs - other attributes mapping,
749 payload - same meaning as for simplexml payload definition
750 timestamp - the time value that needs to be stamped over stanza
751 xmlns - namespace of top stanza node
752 node - parsed or unparsed stana to be taken as prototype.
753 """
754 if not attrs:
755 attrs = {}
756 if to:
757 attrs['to'] = to
758 if frm:
759 attrs['from'] = frm
760 if typ:
761 attrs['type'] = typ
762 Node.__init__(self, tag=name, attrs=attrs, payload=payload, node=node)
763 if not node and xmlns:
764 self.setNamespace(xmlns)
765 if self['to']:
766 self.setTo(self['to'])
767 if self['from']:
768 self.setFrom(self['from'])
769 if node and type(self) == type(node) and \
770 self.__class__ == node.__class__ and self.attrs.has_key('id'):
771 del self.attrs['id']
772 self.timestamp = None
773 for d in self.getTags('delay', namespace=NS_DELAY2):
774 try:
775 if d.getAttr('stamp') < self.getTimestamp2():
776 self.setTimestamp(d.getAttr('stamp'))
777 except Exception:
778 pass
779 if not self.timestamp:
780 for x in self.getTags('x', namespace=NS_DELAY):
781 try:
782 if x.getAttr('stamp') < self.getTimestamp():
783 self.setTimestamp(x.getAttr('stamp'))
784 except Exception:
785 pass
786 if timestamp is not None:
787 self.setTimestamp(timestamp)
788
790 """
791 Return value of the 'to' attribute
792 """
793 try:
794 return self['to']
795 except:
796 return None
797
799 """
800 Return value of the 'from' attribute
801 """
802 try:
803 return self['from']
804 except:
805 return None
806
808 """
809 Return the timestamp in the 'yyyymmddThhmmss' format
810 """
811 if self.timestamp:
812 return self.timestamp
813 return time.strftime('%Y%m%dT%H:%M:%S', time.gmtime())
814
816 """
817 Return the timestamp in the 'yyyymmddThhmmss' format
818 """
819 if self.timestamp:
820 return self.timestamp
821 return time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
822
824 """
825 Return the value of the 'id' attribute
826 """
827 return self.getAttr('id')
828
830 """
831 Set the value of the 'to' attribute
832 """
833 self.setAttr('to', JID(val))
834
836 """
837 Return the value of the 'type' attribute
838 """
839 return self.getAttr('type')
840
842 """
843 Set the value of the 'from' attribute
844 """
845 self.setAttr('from', JID(val))
846
848 """
849 Set the value of the 'type' attribute
850 """
851 self.setAttr('type', val)
852
854 """
855 Set the value of the 'id' attribute
856 """
857 self.setAttr('id', val)
858
860 """
861 Return the error-condition (if present) or the textual description
862 of the error (otherwise)
863 """
864 errtag = self.getTag('error')
865 if errtag:
866 for tag in errtag.getChildren():
867 if tag.getName() != 'text':
868 return tag.getName()
869 return errtag.getData()
870
872 """
873 Return the textual description of the error (if present)
874 or the error condition
875 """
876 errtag = self.getTag('error')
877 if errtag:
878 for tag in errtag.getChildren():
879 if tag.getName() == 'text':
880 return tag.getData()
881 return self.getError()
882
884 """
885 Return the error code. Obsolete.
886 """
887 return self.getTagAttr('error', 'code')
888
890 """
891 Return the status conditions list as defined in XEP-0306.
892 """
893 conds = []
894 condtag = self.getTag('conditions', namespace=NS_CONDITIONS)
895 if condtag:
896 for tag in condtag.getChildren():
897 conds.append(tag.getName())
898 return conds
899
914
916 """
917 Set the timestamp. timestamp should be the yyyymmddThhmmss string
918 """
919 if not val:
920 val = time.strftime('%Y%m%dT%H:%M:%S', time.gmtime())
921 self.timestamp=val
922 self.setTag('x', {'stamp': self.timestamp}, namespace=NS_DELAY)
923
925 """
926 Return the list of namespaces to which belongs the direct childs of element
927 """
928 props = []
929 for child in self.getChildren():
930 prop = child.getNamespace()
931 if prop not in props:
932 props.append(prop)
933 return props
934
936 """
937 Set the item 'item' to the value 'val'
938 """
939 if item in ['to', 'from']:
940 val = JID(val)
941 return self.setAttr(item, val)
942
943
945 """
946 XMPP Message stanza - "push" mechanism
947 """
948
949 - def __init__(self, to=None, body=None, xhtml=None, typ=None, subject=None,
950 attrs={}, frm=None, payload=[], timestamp=None, xmlns=NS_CLIENT,
951 node=None):
952 """
953 You can specify recipient, text of message, type of message any
954 additional attributes, sender of the message, any additional payload
955 (f.e. jabber:x:delay element) and namespace in one go.
956
957 Alternatively you can pass in the other XML object as the 'node'
958 parameted to replicate it as message
959 """
960 Protocol.__init__(self, 'message', to=to, typ=typ, attrs=attrs, frm=frm,
961 payload=payload, timestamp=timestamp, xmlns=xmlns, node=node)
962 if body:
963 self.setBody(body)
964 if xhtml:
965 self.setXHTML(xhtml)
966 if subject is not None:
967 self.setSubject(subject)
968
970 """
971 Return text of the message
972 """
973 return self.getTagData('body')
974
976 """
977 Return serialized xhtml-im element text of the message
978
979 TODO: Returning a DOM could make rendering faster.
980 """
981 xhtml = self.getTag('html')
982 if xhtml:
983 if xmllang:
984 body = xhtml.getTag('body', attrs={'xml:lang': xmllang})
985 else:
986 body = xhtml.getTag('body')
987 return str(body)
988 return None
989
991 """
992 Return subject of the message
993 """
994 return self.getTagData('subject')
995
997 """
998 Return thread of the message
999 """
1000 return self.getTagData('thread')
1001
1002 - def setBody(self, val):
1003 """
1004 Set the text of the message"""
1005 self.setTagData('body', val)
1006
1007 - def setXHTML(self, val, xmllang=None):
1008 """
1009 Sets the xhtml text of the message (XEP-0071). The parameter is the
1010 "inner html" to the body.
1011 """
1012 try:
1013 if xmllang:
1014 dom = NodeBuilder('<body xmlns="%s" xml:lang="%s">%s</body>' \
1015 % (NS_XHTML, xmllang, val)).getDom()
1016 else:
1017 dom = NodeBuilder('<body xmlns="%s">%s</body>' % (NS_XHTML,
1018 val), 0).getDom()
1019 if self.getTag('html'):
1020 self.getTag('html').addChild(node=dom)
1021 else:
1022 self.setTag('html', namespace=NS_XHTML_IM).addChild(node=dom)
1023 except Exception, e:
1024 print "Error", e
1025
1026
1028 """
1029 Set the subject of the message
1030 """
1031 self.setTagData('subject', val)
1032
1034 """
1035 Set the thread of the message
1036 """
1037 self.setTagData('thread', val)
1038
1040 """
1041 Builds and returns another message object with specified text. The to,
1042 from, thread and type properties of new message are pre-set as reply to
1043 this message
1044 """
1045 m = Message(to=self.getFrom(), frm=self.getTo(), body=text,
1046 typ=self.getType())
1047 th = self.getThread()
1048 if th:
1049 m.setThread(th)
1050 return m
1051
1053 """
1054 Return the status code of the message (for groupchat config change)
1055 """
1056 attrs = []
1057 for xtag in self.getTags('x'):
1058 for child in xtag.getTags('status'):
1059 attrs.append(child.getAttr('code'))
1060 return attrs
1061
1063
1064 - def __init__(self, to=None, typ=None, priority=None, show=None, status=None,
1065 attrs={}, frm=None, timestamp=None, payload=[], xmlns=NS_CLIENT,
1066 node=None):
1067 """
1068 You can specify recipient, type of message, priority, show and status
1069 values any additional attributes, sender of the presence, timestamp, any
1070 additional payload (f.e. jabber:x:delay element) and namespace in one go.
1071 Alternatively you can pass in the other XML object as the 'node'
1072 parameted to replicate it as presence
1073 """
1074 Protocol.__init__(self, 'presence', to=to, typ=typ, attrs=attrs, frm=frm,
1075 payload=payload, timestamp=timestamp, xmlns=xmlns, node=node)
1076 if priority:
1077 self.setPriority(priority)
1078 if show:
1079 self.setShow(show)
1080 if status:
1081 self.setStatus(status)
1082
1084 """
1085 Return the priority of the message
1086 """
1087 return self.getTagData('priority')
1088
1090 """
1091 Return the show value of the message
1092 """
1093 return self.getTagData('show')
1094
1096 """
1097 Return the status string of the message
1098 """
1099 return self.getTagData('status')
1100
1102 """
1103 Set the priority of the message
1104 """
1105 self.setTagData('priority', val)
1106
1108 """
1109 Set the show value of the message
1110 """
1111 self.setTagData('show', val)
1112
1114 """
1115 Set the status string of the message
1116 """
1117 self.setTagData('status', val)
1118
1125
1134
1136 """
1137 Return the presence role (for groupchat)
1138 """
1139 return self._muc_getItemAttr('item', 'role')
1140
1142 """
1143 Return the presence affiliation (for groupchat)
1144 """
1145 return self._muc_getItemAttr('item', 'affiliation')
1146
1148 """
1149 Return the status code of the presence (for groupchat)
1150 """
1151 return self._muc_getItemAttr('item', 'nick')
1152
1154 """
1155 Return the presence jid (for groupchat)
1156 """
1157 return self._muc_getItemAttr('item', 'jid')
1158
1160 """
1161 Returns the reason of the presence (for groupchat)
1162 """
1163 return self._muc_getSubTagDataAttr('reason', '')[0]
1164
1166 """
1167 Return the reason of the presence (for groupchat)
1168 """
1169 return self._muc_getSubTagDataAttr('actor', 'jid')[1]
1170
1172 """
1173 Return the status code of the presence (for groupchat)
1174 """
1175 attrs = []
1176 for xtag in self.getTags('x'):
1177 for child in xtag.getTags('status'):
1178 attrs.append(child.getAttr('code'))
1179 return attrs
1180
1181 -class Iq(Protocol):
1182 """
1183 XMPP Iq object - get/set dialog mechanism
1184 """
1185
1186 - def __init__(self, typ=None, queryNS=None, attrs={}, to=None, frm=None,
1187 payload=[], xmlns=NS_CLIENT, node=None):
1188 """
1189 You can specify type, query namespace any additional attributes,
1190 recipient of the iq, sender of the iq, any additional payload (f.e.
1191 jabber:x:data node) and namespace in one go.
1192
1193 Alternatively you can pass in the other XML object as the 'node'
1194 parameted to replicate it as an iq
1195 """
1196 Protocol.__init__(self, 'iq', to=to, typ=typ, attrs=attrs, frm=frm,
1197 xmlns=xmlns, node=node)
1198 if payload:
1199 self.setQueryPayload(payload)
1200 if queryNS:
1201 self.setQueryNS(queryNS)
1202
1204 """
1205 Return the IQ's child element if it exists, None otherwise.
1206 """
1207 children = self.getChildren()
1208 if children and self.getType() != 'error' and \
1209 children[0].getName() != 'error':
1210 return children[0]
1211
1213 """
1214 Return the namespace of the 'query' child element
1215 """
1216 tag = self.getQuery()
1217 if tag:
1218 return tag.getNamespace()
1219
1221 """
1222 Return the 'node' attribute value of the 'query' child element
1223 """
1224 tag = self.getQuery()
1225 if tag:
1226 return tag.getAttr('node')
1227
1229 """
1230 Return the 'query' child element payload
1231 """
1232 tag = self.getQuery()
1233 if tag:
1234 return tag.getPayload()
1235
1237 """
1238 Return the 'query' child element child nodes
1239 """
1240 tag = self.getQuery()
1241 if tag:
1242 return tag.getChildren()
1243
1245 """
1246 Change the name of the query node, creating it if needed. Keep the
1247 existing name if none is given (use 'query' if it's a creation).
1248 Return the query node.
1249 """
1250 query = self.getQuery()
1251 if query is None:
1252 query = self.addChild('query')
1253 if name is not None:
1254 query.setName(name)
1255 return query
1256
1258 """
1259 Set the namespace of the 'query' child element
1260 """
1261 self.setQuery().setNamespace(namespace)
1262
1264 """
1265 Set the 'query' child element payload
1266 """
1267 self.setQuery().setPayload(payload)
1268
1270 """
1271 Set the 'node' attribute value of the 'query' child element
1272 """
1273 self.setQuery().setAttr('node', node)
1274
1276 """
1277 Build and return another Iq object of specified type. The to, from and
1278 query child node of new Iq are pre-set as reply to this Iq.
1279 """
1280 iq = Iq(typ, to=self.getFrom(), frm=self.getTo(),
1281 attrs={'id': self.getID()})
1282 iq.setQuery(self.getQuery().getName()).setNamespace(self.getQueryNS())
1283 return iq
1284
1286 """
1287 Hash elements for various XEPs as defined in XEP-300
1288 """
1289
1290 """
1291 RECOMENDED HASH USE:
1292 Algorithm Support
1293 MD2 MUST NOT
1294 MD4 MUST NOT
1295 MD5 MAY
1296 SHA-1 MUST
1297 SHA-256 MUST
1298 SHA-512 SHOULD
1299 """
1300
1301 supported = ('md5', 'sha-1', 'sha-256', 'sha-512')
1302
1307
1309 """
1310 Calculate the hash and add it. It is preferable doing it here
1311 instead of doing it all over the place in Gajim.
1312 """
1313 hl = None
1314 hash_ = None
1315
1316 if type(file_string) == str:
1317 if algo == 'sha-1':
1318 hl = hashlib.sha1()
1319 elif algo == 'md5':
1320 hl = hashlib.md5()
1321 elif algo == 'sha-256':
1322 hl = hashlib.sha256()
1323 elif algo == 'sha-512':
1324 hl = hashlib.sha512()
1325 if hl:
1326 hl.update(file_string)
1327 hash_ = hl.hexdigest()
1328 else:
1329 if algo == 'sha-1':
1330 hl = hashlib.sha1()
1331 elif algo == 'md5':
1332 hl = hashlib.md5()
1333 elif algo == 'sha-256':
1334 hl = hashlib.sha256()
1335 elif algo == 'sha-512':
1336 hl = hashlib.sha512()
1337 if hl:
1338 for line in file_string:
1339 hl.update(line)
1340 hash_ = hl.hexdigest()
1341 return hash_
1342
1346
1348 """
1349 Acknowledgement elements for Stream Management
1350 """
1354
1356 """
1357 handled is the number of stanzas handled
1358 """
1359 self.setName('a')
1360 self.setAttr('h', handled)
1361
1364
1366 self.setName('enable')
1367 if resume:
1368 self.setAttr('resume', 'true')
1369
1374
1376 """
1377 XMPP-style error element
1378
1379 In the case of stanza error should be attached to XMPP stanza.
1380 In the case of stream-level errors should be used separately.
1381 """
1382
1383 - def __init__(self, name, code=None, typ=None, text=None):
1384 """
1385 Mandatory parameter: name - name of error condition.
1386 Optional parameters: code, typ, text.
1387 Used for backwards compartibility with older jabber protocol.
1388 """
1389 if name in ERRORS:
1390 cod, type_, txt = ERRORS[name]
1391 ns = name.split()[0]
1392 else:
1393 cod, ns, type_, txt = '500', NS_STANZAS, 'cancel', ''
1394 if typ:
1395 type_ = typ
1396 if code:
1397 cod = code
1398 if text:
1399 txt = text
1400 Node.__init__(self, 'error', {}, [Node(name)])
1401 if type_:
1402 self.setAttr('type', type_)
1403 if not cod:
1404 self.setName('stream:error')
1405 if txt:
1406 self.addChild(node=Node(ns + ' text', {}, [txt]))
1407 if cod:
1408 self.setAttr('code', cod)
1409
1411 """
1412 Used to quickly transform received stanza into error reply
1413 """
1414
1415 - def __init__(self, node, error, reply=1):
1416 """
1417 Create error reply basing on the received 'node' stanza and the 'error'
1418 error condition
1419
1420 If the 'node' is not the received stanza but locally created ('to' and
1421 'from' fields needs not swapping) specify the 'reply' argument as false.
1422 """
1423 if reply:
1424 Protocol.__init__(self, to=node.getFrom(), frm=node.getTo(), node=node)
1425 else:
1426 Protocol.__init__(self, node=node)
1427 self.setError(error)
1428 if node.getType() == 'error':
1429 self.__str__ = self.__dupstr__
1430
1432 """
1433 Dummy function used as preventor of creating error node in reply to error
1434 node. I.e. you will not be able to serialise "double" error into string.
1435 """
1436 return ''
1437
1439 """
1440 This class is used in the DataForm class to describe the single data item
1441
1442 If you are working with jabber:x:data (XEP-0004, XEP-0068, XEP-0122) then
1443 you will need to work with instances of this class.
1444 """
1445
1446 - def __init__(self, name=None, value=None, typ=None, required=0, desc=None,
1447 options=[], node=None):
1448 """
1449 Create new data field of specified name,value and type
1450
1451 Also 'required','desc' and 'options' fields can be set. Alternatively
1452 other XML object can be passed in as the 'node' parameted
1453 to replicate it as a new datafiled.
1454 """
1455 Node.__init__(self, 'field', node=node)
1456 if name:
1457 self.setVar(name)
1458 if isinstance(value, (list, tuple)):
1459 self.setValues(value)
1460 elif value:
1461 self.setValue(value)
1462 if typ:
1463 self.setType(typ)
1464 elif not typ and not node:
1465 self.setType('text-single')
1466 if required:
1467 self.setRequired(required)
1468 if desc:
1469 self.setDesc(desc)
1470 if options:
1471 self.setOptions(options)
1472
1474 """
1475 Change the state of the 'required' flag
1476 """
1477 if req:
1478 self.setTag('required')
1479 else:
1480 try:
1481 self.delChild('required')
1482 except ValueError:
1483 return
1484
1486 """
1487 Return in this field a required one
1488 """
1489 return self.getTag('required')
1490
1492 """
1493 Set the description of this field
1494 """
1495 self.setTagData('desc', desc)
1496
1498 """
1499 Return the description of this field
1500 """
1501 return self.getTagData('desc')
1502
1504 """
1505 Set the value of this field
1506 """
1507 self.setTagData('value', val)
1508
1511
1513 """
1514 Set the values of this field as values-list. Replaces all previous filed
1515 values! If you need to just add a value - use addValue method
1516 """
1517 while self.getTag('value'):
1518 self.delChild('value')
1519 for val in lst:
1520 self.addValue(val)
1521
1523 """
1524 Add one more value to this field. Used in 'get' iq's or such
1525 """
1526 self.addChild('value', {}, [val])
1527
1529 """
1530 Return the list of values associated with this field
1531 """
1532 ret = []
1533 for tag in self.getTags('value'):
1534 ret.append(tag.getData())
1535 return ret
1536
1538 """
1539 Return label-option pairs list associated with this field
1540 """
1541 ret = []
1542 for tag in self.getTags('option'):
1543 ret.append([tag.getAttr('label'), tag.getTagData('value')])
1544 return ret
1545
1547 """
1548 Set label-option pairs list associated with this field
1549 """
1550 while self.getTag('option'):
1551 self.delChild('option')
1552 for opt in lst:
1553 self.addOption(opt)
1554
1556 """
1557 Add one more label-option pair to this field
1558 """
1559 if isinstance(opt, basestring):
1560 self.addChild('option').setTagData('value', opt)
1561 else:
1562 self.addChild('option', {'label': opt[0]}).setTagData('value',
1563 opt[1])
1564
1566 """
1567 Get type of this field
1568 """
1569 return self.getAttr('type')
1570
1572 """
1573 Set type of this field
1574 """
1575 return self.setAttr('type', val)
1576
1578 """
1579 Get 'var' attribute value of this field
1580 """
1581 return self.getAttr('var')
1582
1584 """
1585 Set 'var' attribute value of this field
1586 """
1587 return self.setAttr('var', val)
1588
1729