1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """
18 Protocol module contains tools that is needed for processing of
19 xmpp-related data structures.
20 """
21
22 from simplexml import Node,ustr
23 import time
24 NS_ACTIVITY ='http://jabber.org/protocol/activity'
25 NS_ADDRESS ='http://jabber.org/protocol/address'
26 NS_ADMIN ='http://jabber.org/protocol/admin'
27 NS_ADMIN_ADD_USER =NS_ADMIN+'#add-user'
28 NS_ADMIN_DELETE_USER =NS_ADMIN+'#delete-user'
29 NS_ADMIN_DISABLE_USER =NS_ADMIN+'#disable-user'
30 NS_ADMIN_REENABLE_USER =NS_ADMIN+'#reenable-user'
31 NS_ADMIN_END_USER_SESSION =NS_ADMIN+'#end-user-session'
32 NS_ADMIN_GET_USER_PASSWORD =NS_ADMIN+'#get-user-password'
33 NS_ADMIN_CHANGE_USER_PASSWORD =NS_ADMIN+'#change-user-password'
34 NS_ADMIN_GET_USER_ROSTER =NS_ADMIN+'#get-user-roster'
35 NS_ADMIN_GET_USER_LASTLOGIN =NS_ADMIN+'#get-user-lastlogin'
36 NS_ADMIN_USER_STATS =NS_ADMIN+'#user-stats'
37 NS_ADMIN_EDIT_BLACKLIST =NS_ADMIN+'#edit-blacklist'
38 NS_ADMIN_EDIT_WHITELIST =NS_ADMIN+'#edit-whitelist'
39 NS_ADMIN_REGISTERED_USERS_NUM =NS_ADMIN+'#get-registered-users-num'
40 NS_ADMIN_DISABLED_USERS_NUM =NS_ADMIN+'#get-disabled-users-num'
41 NS_ADMIN_ONLINE_USERS_NUM =NS_ADMIN+'#get-online-users-num'
42 NS_ADMIN_ACTIVE_USERS_NUM =NS_ADMIN+'#get-active-users-num'
43 NS_ADMIN_IDLE_USERS_NUM =NS_ADMIN+'#get-idle-users-num'
44 NS_ADMIN_REGISTERED_USERS_LIST =NS_ADMIN+'#get-registered-users-list'
45 NS_ADMIN_DISABLED_USERS_LIST =NS_ADMIN+'#get-disabled-users-list'
46 NS_ADMIN_ONLINE_USERS_LIST =NS_ADMIN+'#get-online-users-list'
47 NS_ADMIN_ACTIVE_USERS_LIST =NS_ADMIN+'#get-active-users-list'
48 NS_ADMIN_IDLE_USERS_LIST =NS_ADMIN+'#get-idle-users-list'
49 NS_ADMIN_ANNOUNCE =NS_ADMIN+'#announce'
50 NS_ADMIN_SET_MOTD =NS_ADMIN+'#set-motd'
51 NS_ADMIN_EDIT_MOTD =NS_ADMIN+'#edit-motd'
52 NS_ADMIN_DELETE_MOTD =NS_ADMIN+'#delete-motd'
53 NS_ADMIN_SET_WELCOME =NS_ADMIN+'#set-welcome'
54 NS_ADMIN_DELETE_WELCOME =NS_ADMIN+'#delete-welcome'
55 NS_ADMIN_EDIT_ADMIN =NS_ADMIN+'#edit-admin'
56 NS_ADMIN_RESTART =NS_ADMIN+'#restart'
57 NS_ADMIN_SHUTDOWN =NS_ADMIN+'#shutdown'
58 NS_AGENTS ='jabber:iq:agents'
59 NS_AMP ='http://jabber.org/protocol/amp'
60 NS_AMP_ERRORS =NS_AMP+'#errors'
61 NS_AUTH ='jabber:iq:auth'
62 NS_AVATAR ='jabber:iq:avatar'
63 NS_BIND ='urn:ietf:params:xml:ns:xmpp-bind'
64 NS_BROWSE ='jabber:iq:browse'
65 NS_BYTESTREAM ='http://jabber.org/protocol/bytestreams'
66 NS_CAPS ='http://jabber.org/protocol/caps'
67 NS_CHATSTATES ='http://jabber.org/protocol/chatstates'
68 NS_CLIENT ='jabber:client'
69 NS_COMMANDS ='http://jabber.org/protocol/commands'
70 NS_COMPONENT_ACCEPT ='jabber:component:accept'
71 NS_COMPONENT_1 ='http://jabberd.jabberstudio.org/ns/component/1.0'
72 NS_COMPRESS ='http://jabber.org/protocol/compress'
73 NS_DATA ='jabber:x:data'
74 NS_DELAY ='jabber:x:delay'
75 NS_DIALBACK ='jabber:server:dialback'
76 NS_DISCO ='http://jabber.org/protocol/disco'
77 NS_DISCO_INFO =NS_DISCO+'#info'
78 NS_DISCO_ITEMS =NS_DISCO+'#items'
79 NS_ENCRYPTED ='jabber:x:encrypted'
80 NS_EVENT ='jabber:x:event'
81 NS_FEATURE ='http://jabber.org/protocol/feature-neg'
82 NS_FILE ='http://jabber.org/protocol/si/profile/file-transfer'
83 NS_GATEWAY ='jabber:iq:gateway'
84 NS_GEOLOC ='http://jabber.org/protocol/geoloc'
85 NS_GROUPCHAT ='gc-1.0'
86 NS_HTTP_BIND ='http://jabber.org/protocol/httpbind'
87 NS_IBB ='http://jabber.org/protocol/ibb'
88 NS_INVISIBLE ='presence-invisible'
89 NS_IQ ='iq'
90 NS_LAST ='jabber:iq:last'
91 NS_MESSAGE ='message'
92 NS_MOOD ='http://jabber.org/protocol/mood'
93 NS_MUC ='http://jabber.org/protocol/muc'
94 NS_MUC_ADMIN =NS_MUC+'#admin'
95 NS_MUC_OWNER =NS_MUC+'#owner'
96 NS_MUC_UNIQUE =NS_MUC+'#unique'
97 NS_MUC_USER =NS_MUC+'#user'
98 NS_MUC_REGISTER =NS_MUC+'#register'
99 NS_MUC_REQUEST =NS_MUC+'#request'
100 NS_MUC_ROOMCONFIG =NS_MUC+'#roomconfig'
101 NS_MUC_ROOMINFO =NS_MUC+'#roominfo'
102 NS_MUC_ROOMS =NS_MUC+'#rooms'
103 NS_MUC_TRAFIC =NS_MUC+'#traffic'
104 NS_OFFLINE ='http://jabber.org/protocol/offline'
105 NS_PHYSLOC ='http://jabber.org/protocol/physloc'
106 NS_PRESENCE ='presence'
107 NS_PRIVACY ='jabber:iq:privacy'
108 NS_PRIVATE ='jabber:iq:private'
109 NS_PUBSUB ='http://jabber.org/protocol/pubsub'
110 NS_REGISTER ='jabber:iq:register'
111 NS_ROSTER ='jabber:iq:roster'
112 NS_ROSTERX ='http://jabber.org/protocol/rosterx'
113 NS_RPC ='jabber:iq:rpc'
114 NS_SASL ='urn:ietf:params:xml:ns:xmpp-sasl'
115 NS_SEARCH ='jabber:iq:search'
116 NS_SERVER ='jabber:server'
117 NS_SESSION ='urn:ietf:params:xml:ns:xmpp-session'
118 NS_SI ='http://jabber.org/protocol/si'
119 NS_SI_PUB ='http://jabber.org/protocol/sipub'
120 NS_SIGNED ='jabber:x:signed'
121 NS_STANZAS ='urn:ietf:params:xml:ns:xmpp-stanzas'
122 NS_STREAMS ='http://etherx.jabber.org/streams'
123 NS_TIME ='jabber:iq:time'
124 NS_TLS ='urn:ietf:params:xml:ns:xmpp-tls'
125 NS_VACATION ='http://jabber.org/protocol/vacation'
126 NS_VCARD ='vcard-temp'
127 NS_VERSION ='jabber:iq:version'
128 NS_WAITINGLIST ='http://jabber.org/protocol/waitinglist'
129 NS_XHTML_IM ='http://jabber.org/protocol/xhtml-im'
130 NS_DATA_LAYOUT ='http://jabber.org/protocol/xdata-layout'
131 NS_DATA_VALIDATE ='http://jabber.org/protocol/xdata-validate'
132 NS_XMPP_STREAMS ='urn:ietf:params:xml:ns:xmpp-streams'
133
134 xmpp_stream_error_conditions="""
135 bad-format -- -- -- The entity has sent XML that cannot be processed.
136 bad-namespace-prefix -- -- -- The entity has sent a namespace prefix that is unsupported, or has sent no namespace prefix on an element that requires such a prefix.
137 conflict -- -- -- The server is closing the active stream for this entity because a new stream has been initiated that conflicts with the existing stream.
138 connection-timeout -- -- -- The entity has not generated any traffic over the stream for some period of time.
139 host-gone -- -- -- 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.
140 host-unknown -- -- -- 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.
141 improper-addressing -- -- -- A stanza sent between two servers lacks a 'to' or 'from' attribute (or the attribute has no value).
142 internal-server-error -- -- -- The server has experienced a misconfiguration or an otherwise-undefined internal error that prevents it from servicing the stream.
143 invalid-from -- cancel -- -- 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.
144 invalid-id -- -- -- The stream ID or dialback ID is invalid or does not match an ID previously provided.
145 invalid-namespace -- -- -- 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".
146 invalid-xml -- -- -- The entity has sent invalid XML over the stream to a server that performs validation.
147 not-authorized -- -- -- 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.
148 policy-violation -- -- -- The entity has violated some local service policy.
149 remote-connection-failed -- -- -- The server is unable to properly connect to a remote resource that is required for authentication or authorization.
150 resource-constraint -- -- -- The server lacks the system resources necessary to service the stream.
151 restricted-xml -- -- -- The entity has attempted to send restricted XML features such as a comment, processing instruction, DTD, entity reference, or unescaped character.
152 see-other-host -- -- -- The server will not provide service to the initiating entity but is redirecting traffic to another host.
153 system-shutdown -- -- -- The server is being shut down and all active streams are being closed.
154 undefined-condition -- -- -- The error condition is not one of those defined by the other conditions in this list.
155 unsupported-encoding -- -- -- The initiating entity has encoded the stream in an encoding that is not supported by the server.
156 unsupported-stanza-type -- -- -- The initiating entity has sent a first-level child of the stream that is not supported by the server.
157 unsupported-version -- -- -- 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.
158 xml-not-well-formed -- -- -- The initiating entity has sent XML that is not well-formed."""
159 xmpp_stanza_error_conditions="""
160 bad-request -- 400 -- modify -- The sender has sent XML that is malformed or that cannot be processed.
161 conflict -- 409 -- cancel -- Access cannot be granted because an existing resource or session exists with the same name or address.
162 feature-not-implemented -- 501 -- cancel -- The feature requested is not implemented by the recipient or server and therefore cannot be processed.
163 forbidden -- 403 -- auth -- The requesting entity does not possess the required permissions to perform the action.
164 gone -- 302 -- modify -- The recipient or server can no longer be contacted at this address.
165 internal-server-error -- 500 -- wait -- The server could not process the stanza because of a misconfiguration or an otherwise-undefined internal server error.
166 item-not-found -- 404 -- cancel -- The addressed JID or item requested cannot be found.
167 jid-malformed -- 400 -- modify -- The value of the 'to' attribute in the sender's stanza does not adhere to the syntax defined in Addressing Scheme.
168 not-acceptable -- 406 -- cancel -- 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.
169 not-allowed -- 405 -- cancel -- The recipient or server does not allow any entity to perform the action.
170 not-authorized -- 401 -- auth -- The sender must provide proper credentials before being allowed to perform the action, or has provided improper credentials.
171 payment-required -- 402 -- auth -- The requesting entity is not authorized to access the requested service because payment is required.
172 recipient-unavailable -- 404 -- wait -- The intended recipient is temporarily unavailable.
173 redirect -- 302 -- modify -- The recipient or server is redirecting requests for this information to another entity.
174 registration-required -- 407 -- auth -- The requesting entity is not authorized to access the requested service because registration is required.
175 remote-server-not-found -- 404 -- cancel -- A remote server or service specified as part or all of the JID of the intended recipient does not exist.
176 remote-server-timeout -- 504 -- wait -- 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.
177 resource-constraint -- 500 -- wait -- The server or recipient lacks the system resources necessary to service the request.
178 service-unavailable -- 503 -- cancel -- The server or recipient does not currently provide the requested service.
179 subscription-required -- 407 -- auth -- The requesting entity is not authorized to access the requested service because a subscription is required.
180 undefined-condition -- 500 -- --
181 unexpected-request -- 400 -- wait -- The recipient or server understood the request but was not expecting it at this time (e.g., the request was out of order)."""
182 sasl_error_conditions="""
183 aborted -- -- -- The receiving entity acknowledges an <abort/> element sent by the initiating entity; sent in reply to the <abort/> element.
184 incorrect-encoding -- -- -- 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.
185 invalid-authzid -- -- -- 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.
186 invalid-mechanism -- -- -- 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.
187 mechanism-too-weak -- -- -- 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.
188 not-authorized -- -- -- 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.
189 temporary-auth-failure -- -- -- The authentication failed because of a temporary error condition within the receiving entity; sent in reply to an <auth/> element or <response/> element."""
190
191 ERRORS,_errorcodes={},{}
192 for ns,errname,errpool in [(NS_XMPP_STREAMS,'STREAM',xmpp_stream_error_conditions),
193 (NS_STANZAS ,'ERR' ,xmpp_stanza_error_conditions),
194 (NS_SASL ,'SASL' ,sasl_error_conditions)]:
195 for err in errpool.split('\n')[1:]:
196 cond,code,typ,text=err.split(' -- ')
197 name=errname+'_'+cond.upper().replace('-','_')
198 locals()[name]=ns+' '+cond
199 ERRORS[ns+' '+cond]=[code,typ,text]
200 if code: _errorcodes[code]=cond
201 del ns,errname,errpool,err,cond,code,typ,text
202
204 """ Returns true if the node is a positive reply. """
205 return node and node.getType()=='result'
207 """ Returns true if the node is a negative reply. """
208 return node and node.getType()=='error'
209
211 """ Exception that should be raised by handler when the handling should be stopped. """
213 """ Base exception class for stream errors."""
238
239 stream_exceptions = {'bad-format': BadFormat,
240 'bad-namespace-prefix': BadNamespacePrefix,
241 'conflict': Conflict,
242 'connection-timeout': ConnectionTimeout,
243 'host-gone': HostGone,
244 'host-unknown': HostUnknown,
245 'improper-addressing': ImproperAddressing,
246 'internal-server-error': InternalServerError,
247 'invalid-from': InvalidFrom,
248 'invalid-id': InvalidID,
249 'invalid-namespace': InvalidNamespace,
250 'invalid-xml': InvalidXML,
251 'not-authorized': NotAuthorized,
252 'policy-violation': PolicyViolation,
253 'remote-connection-failed': RemoteConnectionFailed,
254 'resource-constraint': ResourceConstraint,
255 'restricted-xml': RestrictedXML,
256 'see-other-host': SeeOtherHost,
257 'system-shutdown': SystemShutdown,
258 'undefined-condition': UndefinedCondition,
259 'unsupported-encoding': UnsupportedEncoding,
260 'unsupported-stanza-type': UnsupportedStanzaType,
261 'unsupported-version': UnsupportedVersion,
262 'xml-not-well-formed': XMLNotWellFormed}
263
265 """ JID object. JID can be built from string, modified, compared, serialised into string. """
266 - def __init__(self, jid=None, node='', domain='', resource=''):
267 """ Constructor. JID can be specified as string (jid argument) or as separate parts.
268 Examples:
269 JID('node@domain/resource')
270 JID(node='node',domain='domain.org')
271 """
272 if not jid and not domain: raise ValueError('JID must contain at least domain name')
273 elif type(jid)==type(self): self.node,self.domain,self.resource=jid.node,jid.domain,jid.resource
274 elif domain: self.node,self.domain,self.resource=node,domain,resource
275 else:
276 if jid.find('@')+1: self.node,jid=jid.split('@',1)
277 else: self.node=''
278 if jid.find('/')+1: self.domain,self.resource=jid.split('/',1)
279 else: self.domain,self.resource=jid,''
281 """ Return the node part of the JID """
282 return self.node
284 """ Set the node part of the JID to new value. Specify None to remove the node part."""
285 self.node=node.lower()
286 - def getDomain(self):
287 """ Return the domain part of the JID """
288 return self.domain