Package xmpp :: Module protocol
[hide private]
[frames] | no frames]

Source Code for Module xmpp.protocol

  1  ##   protocol.py  
  2  ## 
  3  ##   Copyright (C) 2003-2005 Alexey "Snake" Nezhdanov 
  4  ## 
  5  ##   This program is free software; you can redistribute it and/or modify 
  6  ##   it under the terms of the GNU General Public License as published by 
  7  ##   the Free Software Foundation; either version 2, or (at your option) 
  8  ##   any later version. 
  9  ## 
 10  ##   This program is distributed in the hope that it will be useful, 
 11  ##   but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  ##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  ##   GNU General Public License for more details. 
 14   
 15  # $Id: protocol.py,v 1.58 2007/05/13 17:55:46 normanr Exp $ 
 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'                  # XEP-0108 
 25  NS_ADDRESS          ='http://jabber.org/protocol/address'                   # XEP-0033 
 26  NS_ADMIN            ='http://jabber.org/protocol/admin'                     # XEP-0133 
 27  NS_ADMIN_ADD_USER               =NS_ADMIN+'#add-user'                       # XEP-0133 
 28  NS_ADMIN_DELETE_USER            =NS_ADMIN+'#delete-user'                    # XEP-0133 
 29  NS_ADMIN_DISABLE_USER           =NS_ADMIN+'#disable-user'                   # XEP-0133 
 30  NS_ADMIN_REENABLE_USER          =NS_ADMIN+'#reenable-user'                  # XEP-0133 
 31  NS_ADMIN_END_USER_SESSION       =NS_ADMIN+'#end-user-session'               # XEP-0133 
 32  NS_ADMIN_GET_USER_PASSWORD      =NS_ADMIN+'#get-user-password'              # XEP-0133 
 33  NS_ADMIN_CHANGE_USER_PASSWORD   =NS_ADMIN+'#change-user-password'           # XEP-0133 
 34  NS_ADMIN_GET_USER_ROSTER        =NS_ADMIN+'#get-user-roster'                # XEP-0133 
 35  NS_ADMIN_GET_USER_LASTLOGIN     =NS_ADMIN+'#get-user-lastlogin'             # XEP-0133 
 36  NS_ADMIN_USER_STATS             =NS_ADMIN+'#user-stats'                     # XEP-0133 
 37  NS_ADMIN_EDIT_BLACKLIST         =NS_ADMIN+'#edit-blacklist'                 # XEP-0133 
 38  NS_ADMIN_EDIT_WHITELIST         =NS_ADMIN+'#edit-whitelist'                 # XEP-0133 
 39  NS_ADMIN_REGISTERED_USERS_NUM   =NS_ADMIN+'#get-registered-users-num'       # XEP-0133 
 40  NS_ADMIN_DISABLED_USERS_NUM     =NS_ADMIN+'#get-disabled-users-num'         # XEP-0133 
 41  NS_ADMIN_ONLINE_USERS_NUM       =NS_ADMIN+'#get-online-users-num'           # XEP-0133 
 42  NS_ADMIN_ACTIVE_USERS_NUM       =NS_ADMIN+'#get-active-users-num'           # XEP-0133 
 43  NS_ADMIN_IDLE_USERS_NUM         =NS_ADMIN+'#get-idle-users-num'             # XEP-0133 
 44  NS_ADMIN_REGISTERED_USERS_LIST  =NS_ADMIN+'#get-registered-users-list'      # XEP-0133 
 45  NS_ADMIN_DISABLED_USERS_LIST    =NS_ADMIN+'#get-disabled-users-list'        # XEP-0133 
 46  NS_ADMIN_ONLINE_USERS_LIST      =NS_ADMIN+'#get-online-users-list'          # XEP-0133 
 47  NS_ADMIN_ACTIVE_USERS_LIST      =NS_ADMIN+'#get-active-users-list'          # XEP-0133 
 48  NS_ADMIN_IDLE_USERS_LIST        =NS_ADMIN+'#get-idle-users-list'            # XEP-0133 
 49  NS_ADMIN_ANNOUNCE               =NS_ADMIN+'#announce'                       # XEP-0133 
 50  NS_ADMIN_SET_MOTD               =NS_ADMIN+'#set-motd'                       # XEP-0133 
 51  NS_ADMIN_EDIT_MOTD              =NS_ADMIN+'#edit-motd'                      # XEP-0133 
 52  NS_ADMIN_DELETE_MOTD            =NS_ADMIN+'#delete-motd'                    # XEP-0133 
 53  NS_ADMIN_SET_WELCOME            =NS_ADMIN+'#set-welcome'                    # XEP-0133 
 54  NS_ADMIN_DELETE_WELCOME         =NS_ADMIN+'#delete-welcome'                 # XEP-0133 
 55  NS_ADMIN_EDIT_ADMIN             =NS_ADMIN+'#edit-admin'                     # XEP-0133 
 56  NS_ADMIN_RESTART                =NS_ADMIN+'#restart'                        # XEP-0133 
 57  NS_ADMIN_SHUTDOWN               =NS_ADMIN+'#shutdown'                       # XEP-0133 
 58  NS_AGENTS           ='jabber:iq:agents'                                     # XEP-0094 (historical) 
 59  NS_AMP              ='http://jabber.org/protocol/amp'                       # XEP-0079 
 60  NS_AMP_ERRORS                   =NS_AMP+'#errors'                           # XEP-0079 
 61  NS_AUTH             ='jabber:iq:auth' 
 62  NS_AVATAR           ='jabber:iq:avatar'                                     # XEP-0008 (historical) 
 63  NS_BIND             ='urn:ietf:params:xml:ns:xmpp-bind' 
 64  NS_BROWSE           ='jabber:iq:browse'                                     # XEP-0011 (historical) 
 65  NS_BYTESTREAM       ='http://jabber.org/protocol/bytestreams'               # XEP-0065 
 66  NS_CAPS             ='http://jabber.org/protocol/caps'                      # XEP-0115 
 67  NS_CHATSTATES       ='http://jabber.org/protocol/chatstates'                # XEP-0085 
 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'                  # XEP-0138 
 73  NS_DATA             ='jabber:x:data'                                        # XEP-0004 
 74  NS_DELAY            ='jabber:x:delay' 
 75  NS_DIALBACK         ='jabber:server:dialback' 
 76  NS_DISCO            ='http://jabber.org/protocol/disco'                     # XEP-0030 
 77  NS_DISCO_INFO                   =NS_DISCO+'#info'                           # XEP-0030 
 78  NS_DISCO_ITEMS                  =NS_DISCO+'#items'                          # XEP-0030 
 79  NS_ENCRYPTED        ='jabber:x:encrypted'                                   # XEP-0027 
 80  NS_EVENT            ='jabber:x:event'                                       # XEP-0022 
 81  NS_FEATURE          ='http://jabber.org/protocol/feature-neg'   
 82  NS_FILE             ='http://jabber.org/protocol/si/profile/file-transfer'  # XEP-0096 
 83  NS_GATEWAY          ='jabber:iq:gateway' 
 84  NS_GEOLOC           ='http://jabber.org/protocol/geoloc'                    # XEP-0080 
 85  NS_GROUPCHAT        ='gc-1.0' 
 86  NS_HTTP_BIND        ='http://jabber.org/protocol/httpbind'                  # XEP-0124 
 87  NS_IBB              ='http://jabber.org/protocol/ibb' 
 88  NS_INVISIBLE        ='presence-invisible'                                   # Jabberd2 
 89  NS_IQ               ='iq'                                                   # Jabberd2 
 90  NS_LAST             ='jabber:iq:last' 
 91  NS_MESSAGE          ='message'                                              # Jabberd2 
 92  NS_MOOD             ='http://jabber.org/protocol/mood'                      # XEP-0107 
 93  NS_MUC              ='http://jabber.org/protocol/muc'                       # XEP-0045 
 94  NS_MUC_ADMIN                    =NS_MUC+'#admin'                            # XEP-0045 
 95  NS_MUC_OWNER                    =NS_MUC+'#owner'                            # XEP-0045 
 96  NS_MUC_UNIQUE                   =NS_MUC+'#unique'                           # XEP-0045 
 97  NS_MUC_USER                     =NS_MUC+'#user'                             # XEP-0045 
 98  NS_MUC_REGISTER                 =NS_MUC+'#register'                         # XEP-0045 
 99  NS_MUC_REQUEST                  =NS_MUC+'#request'                          # XEP-0045 
100  NS_MUC_ROOMCONFIG               =NS_MUC+'#roomconfig'                       # XEP-0045 
101  NS_MUC_ROOMINFO                 =NS_MUC+'#roominfo'                         # XEP-0045 
102  NS_MUC_ROOMS                    =NS_MUC+'#rooms'                            # XEP-0045 
103  NS_MUC_TRAFIC                   =NS_MUC+'#traffic'                          # XEP-0045 
104  NS_OFFLINE          ='http://jabber.org/protocol/offline'                   # XEP-0013 
105  NS_PHYSLOC          ='http://jabber.org/protocol/physloc'                   # XEP-0112 
106  NS_PRESENCE         ='presence'                                             # Jabberd2 
107  NS_PRIVACY          ='jabber:iq:privacy' 
108  NS_PRIVATE          ='jabber:iq:private' 
109  NS_PUBSUB           ='http://jabber.org/protocol/pubsub'                    # XEP-0060 
110  NS_REGISTER         ='jabber:iq:register' 
111  NS_ROSTER           ='jabber:iq:roster' 
112  NS_ROSTERX          ='http://jabber.org/protocol/rosterx'                   # XEP-0144 
113  NS_RPC              ='jabber:iq:rpc'                                        # XEP-0009 
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'                        # XEP-0096 
119  NS_SI_PUB           ='http://jabber.org/protocol/sipub'                     # XEP-0137 
120  NS_SIGNED           ='jabber:x:signed'                                      # XEP-0027 
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'               # XEP-0130 
129  NS_XHTML_IM         ='http://jabber.org/protocol/xhtml-im'                  # XEP-0071 
130  NS_DATA_LAYOUT      ='http://jabber.org/protocol/xdata-layout'              # XEP-0141 
131  NS_DATA_VALIDATE    ='http://jabber.org/protocol/xdata-validate'            # XEP-0122 
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   
203 -def isResultNode(node):
204 """ Returns true if the node is a positive reply. """ 205 return node and node.getType()=='result'
206 -def isErrorNode(node):
207 """ Returns true if the node is a negative reply. """ 208 return node and node.getType()=='error'
209
210 -class NodeProcessed(Exception):
211 """ Exception that should be raised by handler when the handling should be stopped. """
212 -class StreamError(Exception):
213 """ Base exception class for stream errors."""
214 -class BadFormat(StreamError): pass
215 -class BadNamespacePrefix(StreamError): pass
216 -class Conflict(StreamError): pass
217 -class ConnectionTimeout(StreamError): pass
218 -class HostGone(StreamError): pass
219 -class HostUnknown(StreamError): pass
220 -class ImproperAddressing(StreamError): pass
221 -class InternalServerError(StreamError): pass
222 -class InvalidFrom(StreamError): pass
223 -class InvalidID(StreamError): pass
224 -class InvalidNamespace(StreamError): pass
225 -class InvalidXML(StreamError): pass
226 -class NotAuthorized(StreamError): pass
227 -class PolicyViolation(StreamError): pass
228 -class RemoteConnectionFailed(StreamError): pass
229 -class ResourceConstraint(StreamError): pass
230 -class RestrictedXML(StreamError): pass
231 -class SeeOtherHost(StreamError): pass
232 -class SystemShutdown(StreamError): pass
233 -class UndefinedCondition(StreamError): pass
234 -class UnsupportedEncoding(StreamError): pass
235 -class UnsupportedStanzaType(StreamError): pass
236 -class UnsupportedVersion(StreamError): pass
237 -class XMLNotWellFormed(StreamError): pass
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
264 -class JID:
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,''
280 - def getNode(self):
281 """ Return the node part of the JID """ 282 return self.node
283 - def setNode(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
289 - def