1  from protocol import Acks 
  2  from protocol import NS_STREAM_MGMT 
  3  import logging 
  4  log = logging.getLogger('nbxmpp.smacks') 
  5   
  7      ''' 
  8      This is Smacks is the Stream Management class. It takes care of requesting 
  9      and sending acks. Also, it keeps track of the unhandled outgoing stanzas. 
 10   
 11      The dispatcher has to be able to access this class to increment the 
 12      number of handled stanzas 
 13      ''' 
 14   
 16          self.con = con  
 17          self.out_h = 0  
 18          self.in_h = 0   
 19          self.uqueue = []  
 20          self.session_id = None 
 21          self.resumption = False  
 22           
 23          self.max_queue = 5 
 24          self._owner = None 
 25          self.resuming = False 
 26          self.enabled = False  
 27          self.location = None 
 28          self.failed_resume = False  
 29          self.supports_sm = False  
  30   
 32          self._owner = owner 
 33           
 34          owner.Dispatcher.RegisterNamespace(NS_STREAM_MGMT) 
 35          owner.Dispatcher.RegisterHandler('enabled', self._neg_response, 
 36              xmlns=NS_STREAM_MGMT) 
 37          owner.Dispatcher.RegisterHandler('r', self.send_ack, 
 38              xmlns=NS_STREAM_MGMT) 
 39          owner.Dispatcher.RegisterHandler('a', self.check_ack, 
 40              xmlns=NS_STREAM_MGMT) 
 41          owner.Dispatcher.RegisterHandler('resumed', self.check_ack, 
 42              xmlns=NS_STREAM_MGMT) 
 43          owner.Dispatcher.RegisterHandler('failed', self.error_handling, 
 44              xmlns=NS_STREAM_MGMT) 
  45   
 47          r = stanza.getAttr('resume') 
 48          if r == 'true' or r == 'True' or r == '1': 
 49              self.resumption = True 
 50              self.session_id = stanza.getAttr('id') 
 51          if r == 'false' or r == 'False' or r == '0': 
 52              self.negociate(False) 
 53          l = stanza.getAttr('location') 
 54          if l: 
 55              self.location = l 
 56          if self.failed_resume: 
 57              self.con._discover_server_at_connection(self.con.connection) 
 58              self.failed_resume = False 
  59   
 61           
 62           
 63          self.uqueue = [] 
 64          self.in_h = 0 
 65          self.out_h = 0 
 66          self.session_id = None 
 67          self.enabled = True 
 68   
 69          stanza = Acks() 
 70          stanza.buildEnable(resume) 
 71          self._owner.Connection.send(stanza, now=True) 
  72   
 74          if not self.session_id: 
 75              self.resuming = False 
 76              log.error('Attempted to resume without a valid session id ') 
 77              return 
 78          resume = Acks() 
 79          resume.buildResume(self.in_h, self.session_id) 
 80          self._owner.Connection.send(resume, False) 
  81   
 86   
 91   
 93          ''' 
 94          Checks if the number of stanzas sent are the same as the 
 95          number of stanzas received by the server. Pops stanzas that were 
 96          handled by the server from the queue. 
 97          ''' 
 98          h = int(stanza.getAttr('h')) 
 99          diff = self.out_h - h 
100   
101          if len(self.uqueue) < diff or diff < 0: 
102              log.error('Server and client number of stanzas handled mismatch ') 
103          else: 
104              while (len(self.uqueue) > diff): 
105                  self.uqueue.pop(0) 
106   
107          if stanza.getName() == 'resumed': 
108              self.enabled = True 
109              self.resuming = True 
110              self.con.set_oldst() 
111              if self.uqueue != []: 
112                  for i in self.uqueue: 
113                      self._owner.Connection.send(i, False) 
 114   
116           
117           
118          if stanza.getTag('item-not-found'): 
119              self.resuming = False 
120              self.enabled = False 
121               
122              self._owner.NonBlockingBind.resuming = False 
123              self._owner._on_auth_bind(None) 
124              self.failed_resume = True 
125              return 
126   
127           
128          if stanza.getTag('feature-not-implemented'): 
129              self.negociate(False) 
130              return 
131   
132          if stanza.getTag('unexpected-request'): 
133              self.enabled = False 
134              log.error('Gajim failed to negociate Stream Management') 
135              return 
  136