1414from urlparse import urlparse
1515from xml .etree import ElementTree as ET
1616
17- from puresasl .client import SASLClient
17+ from puresasl .client import SASLClient
18+ from .conf import get_conversejs_settings
19+
20+
21+ try : # Python 2.7+
22+ from logging import NullHandler
23+ except ImportError :
24+ class NullHandler (logging .Handler ):
25+ def emit (self , record ):
26+ pass
1827
1928
2029HTTPBIND_NS = 'http://jabber.org/protocol/httpbind'
@@ -44,23 +53,27 @@ def __init__(self, jid, password, bosh_service):
4453
4554 self ._connection = None
4655 self ._sid = None
47-
56+
4857 self .jid , self .to = jid .split ('@' )
4958 self .password = password
50- self .bosh_service = urlparse (bosh_service )
51-
59+ self .bosh_service = urlparse (bosh_service )
60+
5261 self .rid = randint (0 , 10000000 )
5362 self .log .debug ('Init RID: %s' % self .rid )
54-
63+
5564 self .headers = {
5665 "Content-Type" : "text/plain; charset=UTF-8" ,
5766 "Accept" : "text/xml" ,
5867 "Accept-Encoding" : "gzip, deflate"
5968 }
60-
69+
6170 self .server_auth = []
62-
63- @property
71+
72+ converse_settings = get_conversejs_settings ()
73+ xml_encoding_line = converse_settings ['CONVERSEJS_XML_ENCODING_LINE' ]
74+ self .xml_encoding_line = True if xml_encoding_line .lower () == 'true' else False
75+
76+ @property
6477 def connection (self ):
6578 """Returns an stablished connection"""
6679
@@ -74,9 +87,9 @@ def connection(self):
7487 elif self .bosh_service .scheme == 'https' :
7588 Connection = httplib .HTTPSConnection
7689 else :
77- # TODO: raise proper exception
90+ # TODO: raise proper exception
7891 raise Exception ('Invalid URL scheme %s' % self .bosh_service .scheme )
79-
92+
8093 self ._connection = Connection (self .bosh_service .netloc )
8194 self .log .debug ('Connection initialized' )
8295 # TODO add exceptions handler there (URL not found etc)
@@ -86,7 +99,7 @@ def connection(self):
8699 def close_connection (self ):
87100 if not self ._connection :
88101 self .log .debug ('Trying to close connection before initializing it.' )
89- return
102+ return
90103
91104 self .log .debug ('Closing connection' )
92105 self .connection .close ()
@@ -99,7 +112,7 @@ def get_body(self, sid_request=False):
99112 body .set ('xmlns' , HTTPBIND_NS )
100113
101114 if sid_request :
102- body .set ('xmlns:xmpp' , BOSH_NS )
115+ body .set ('xmlns:xmpp' , BOSH_NS )
103116 body .set ('wait' , unicode (BOSH_WAIT ))
104117 body .set ('hold' , unicode (BOSH_HOLD ))
105118 body .set ('content' , BOSH_CONTENT )
@@ -112,15 +125,17 @@ def get_body(self, sid_request=False):
112125 body .set ('to' , self .to )
113126
114127 if self ._sid :
115- body .set ('sid' , self .sid )
128+ body .set ('sid' , self .sid )
116129
117130 body .set ('rid' , str (self .rid ))
118131
119132 return body
120133
121134 def send_request (self , xml_stanza ):
122- if isinstance (xml_stanza , ET .Element ):
123- xml_stanza = ET .tostring (xml_stanza , encoding = 'utf8' , method = 'xml' )
135+ ElementType = getattr (ET , '_Element' , ET .Element )
136+ if isinstance (xml_stanza , ElementType ):
137+ xml_stanza = ET .tostring (xml_stanza ) if not self .xml_encoding_line \
138+ else ET .tostring (xml_stanza , encoding = 'utf8' )
124139
125140 self .log .debug ('XML_STANZA: %s' , xml_stanza )
126141 self .log .debug ('Sending the request' )
@@ -147,7 +162,7 @@ def send_request(self, xml_stanza):
147162 def sid (self ):
148163 if self ._sid :
149164 return self ._sid
150-
165+
151166 return self .request_sid ()
152167
153168 def request_sid (self ):
@@ -160,44 +175,44 @@ def request_sid(self):
160175 return self ._sid
161176
162177 self .log .debug ('Prepare to request BOSH session' )
163-
178+
164179 data = self .send_request (self .get_body (sid_request = True ))
165180 if not data :
166181 return None
167-
182+
168183
169184 # This is XML. response_body contains the <body/> element of the
170185 # response.
171186 response_body = ET .fromstring (data )
172-
187+
173188 # Get the remote Session ID
174189 self ._sid = response_body .get ('sid' )
175190 self .log .debug ('sid = %s' % self ._sid )
176-
191+
177192 # Get the longest time (s) that the XMPP server will wait before
178193 # responding to any request.
179194 self .server_wait = response_body .get ('wait' )
180195 self .log .debug ('wait = %s' % self .server_wait )
181-
196+
182197 # Get the authid
183198 self .authid = response_body .get ('authid' )
184-
199+
185200 # Get the allowed authentication methods using xpath
186- search_for = '{{{}}}features/{{{}}}mechanisms/{{{}}}mechanism' .format (
201+ search_for = '{{{0 }}}features/{{{1 }}}mechanisms/{{{2 }}}mechanism' .format (
187202 JABBER_STREAMS_NS , XMPP_SASL_NS , XMPP_SASL_NS )
188203 self .log .debug ('Looking for "%s" into response body' , search_for )
189204 mechanisms = response_body .iterfind (search_for )
190205 self .server_auth = []
191206
192207 for mechanism in mechanisms :
193- self .server_auth .append (mechanism .text )
208+ self .server_auth .append (mechanism .text )
194209 self .log .debug ('New AUTH method: %s' % mechanism .text )
195210
196211 if not self .server_auth :
197212 self .log .debug (('The server didn\' t send the allowed '
198213 'authentication methods' ))
199214 self ._sid = None
200-
215+
201216 return self ._sid
202217
203218 def get_challenge (self , mechanism ):
@@ -207,10 +222,10 @@ def get_challenge(self, mechanism):
207222 auth .set ('mechanism' , mechanism )
208223
209224 resp_root = ET .fromstring (self .send_request (body ))
210- challenge_node = resp_root .find ('{{{}}}challenge' .format (XMPP_SASL_NS ))
225+ challenge_node = resp_root .find ('{{{0 }}}challenge' .format (XMPP_SASL_NS ))
211226
212227 if challenge_node is not None :
213- return challenge_node .text
228+ return challenge_node .text
214229
215230 return None
216231
@@ -222,16 +237,16 @@ def send_challenge_response(self, response_plain):
222237
223238 # Create a response tag and add the response content on it
224239 # using base64 encoding
225- response_node = ET .SubElement (body , 'response' )
240+ response_node = ET .SubElement (body , 'response' )
226241 response_node .set ('xmlns' , XMPP_SASL_NS )
227242 response_node .text = base64 .b64encode (response_plain )
228243
229244 # Send the challenge response to server
230245 resp_root = ET .fromstring (self .send_request (body ))
231246
232247 # Look for the success tag. If it's not present authentication
233- # has failed
234- success = resp_root .find ('{{{}}}success' .format (XMPP_SASL_NS ))
248+ # has failed
249+ success = resp_root .find ('{{{0 }}}success' .format (XMPP_SASL_NS ))
235250 if success is not None :
236251 return True
237252 return False
@@ -243,7 +258,7 @@ def authenticate_xmpp(self):
243258
244259 self .log .debug ('Prepare the XMPP authentication' )
245260
246- # Instantiate a sasl object
261+ # Instantiate a sasl object
247262 sasl = SASLClient (host = self .to ,
248263 service = 'xmpp' ,
249264 username = self .jid ,
@@ -254,7 +269,7 @@ def authenticate_xmpp(self):
254269
255270 # Request challenge
256271 challenge = self .get_challenge (sasl .mechanism )
257-
272+
258273 # Process challenge and generate response
259274 response = sasl .process (base64 .b64decode (challenge ))
260275
@@ -266,7 +281,7 @@ def authenticate_xmpp(self):
266281 self .request_restart ()
267282
268283 self .bind_resource ()
269-
284+
270285 return True
271286
272287 def bind_resource (self ):
@@ -275,10 +290,10 @@ def bind_resource(self):
275290 iq = ET .SubElement (body , 'iq' )
276291 iq .set ('id' , 'bind_1' )
277292 iq .set ('type' , 'set' )
278- iq .set ('xmlns' , JABBER_CLIENT_NS )
293+ iq .set ('xmlns' , JABBER_CLIENT_NS )
279294
280295 bind = ET .SubElement (iq , 'bind' )
281- bind .set ('xmlns' , XMPP_BIND_NS )
296+ bind .set ('xmlns' , XMPP_BIND_NS )
282297
283298 self .send_request (body )
284299
@@ -289,18 +304,18 @@ def request_restart(self):
289304 self .send_request (body )
290305
291306 def get_credentials (self ):
292- success = self .authenticate_xmpp ()
307+ success = self .authenticate_xmpp ()
293308 if not success :
294309 return None , None , None
295310
296- return u'{}@{}' .format (self .jid , self .to ), self .sid , self .rid
297-
311+ return u'{0 }@{1 }' .format (self .jid , self .to ), self .sid , self .rid
312+
298313
299314if __name__ == '__main__' :
300315 import sys
301316
302317 if len (sys .argv ) != 4 :
303- print 'usage: {} SERVICE_URL USERNAME PASSWORD' .format (sys .argv [0 ])
318+ print 'usage: {0 } SERVICE_URL USERNAME PASSWORD' .format (sys .argv [0 ])
304319 sys .exit (1 )
305320
306321 c = BOSHClient (sys .argv [2 ], sys .argv [3 ], sys .argv [1 ])
0 commit comments