diff --git a/src/common/contacts.py b/src/common/contacts.py
index d04486f8b..a4a64a0dd 100644
--- a/src/common/contacts.py
+++ b/src/common/contacts.py
@@ -581,11 +581,10 @@ class MetacontactManager():
#FIXME: can this append ?
assert False
- def get_metacontacts_tags(self, account):
- '''return a list of tags for a given account'''
- if not account in self._metacontacts_tags:
- return []
- return self._metacontacts_tags[account].keys()
+ def iter_metacontacts_families(self, account):
+ for tag in self._metacontacts_tags[account]:
+ family = self._get_metacontacts_family_from_tag(account, tag)
+ yield family
def _get_metacontacts_tag(self, account, jid):
'''Returns the tag of a jid'''
@@ -643,7 +642,7 @@ class MetacontactManager():
tag = self._get_metacontacts_tag(account, jid)
if not tag:
return False
- meta_jids = self.get_metacontacts_jids(tag, accounts)
+ meta_jids = self._get_metacontacts_jids(tag, accounts)
return len(meta_jids) > 1 or len(meta_jids[account]) > 1
def is_big_brother(self, account, jid, accounts):
@@ -651,12 +650,12 @@ class MetacontactManager():
if family:
nearby_family = [data for data in family
if account in accounts]
- bb_data = self.get_metacontacts_big_brother(nearby_family)
+ bb_data = self._get_metacontacts_big_brother(nearby_family)
if bb_data['jid'] == jid and bb_data['account'] == account:
return True
return False
- def get_metacontacts_jids(self, tag, accounts):
+ def _get_metacontacts_jids(self, tag, accounts):
'''Returns all jid for the given tag in the form {acct: [jid1, jid2],.}'''
answers = {}
for account in self._metacontacts_tags:
@@ -673,9 +672,9 @@ class MetacontactManager():
[{'account': acct, 'jid': jid, 'order': order}, ]
'order' is optional'''
tag = self._get_metacontacts_tag(account, jid)
- return self.get_metacontacts_family_from_tag(account, tag)
+ return self._get_metacontacts_family_from_tag(account, tag)
- def get_metacontacts_family_from_tag(self, account, tag):
+ def _get_metacontacts_family_from_tag(self, account, tag):
if not tag:
return []
answers = []
@@ -765,8 +764,30 @@ class MetacontactManager():
if account2 > account1:
return -1
return 0
+
+ def get_nearby_family_and_big_brother(self, family, account):
+ '''Return the nearby family and its Big Brother
- def get_metacontacts_big_brother(self, family):
+ Nearby family is the part of the family that is grouped with the metacontact.
+ A metacontact may be over different accounts. If accounts are not merged
+ then the given family is split account wise.
+
+ (nearby_family, big_brother_jid, big_brother_account)
+ '''
+ if common.gajim.config.get('mergeaccounts'):
+ # group all together
+ nearby_family = family
+ else:
+ # we want one nearby_family per account
+ nearby_family = [data for data in family if account == data['account']]
+
+ big_brother_data = self._get_metacontacts_big_brother(nearby_family)
+ big_brother_jid = big_brother_data['jid']
+ big_brother_account = big_brother_data['account']
+
+ return (nearby_family, big_brother_jid, big_brother_account)
+
+ def _get_metacontacts_big_brother(self, family):
'''which of the family will be the big brother under wich all
others will be ?'''
family.sort(cmp=self._compare_metacontacts)
diff --git a/src/common/xmpp/dispatcher_nb.py b/src/common/xmpp/dispatcher_nb.py
index 98ca5be7a..8f4746f68 100644
--- a/src/common/xmpp/dispatcher_nb.py
+++ b/src/common/xmpp/dispatcher_nb.py
@@ -462,7 +462,10 @@ class XMPPDispatcher(PlugIn):
# we have released dispatcher, so self._owner has no methods
if not res:
return
- self._owner.remove_timeout()
+ if 'remove_timeout' in self._owner.__dict__:
+ # When we receive data after we started disconnecting, Transport may
+ # already be plugged out
+ self._owner.remove_timeout()
for (_id, _iq) in self._expected.items():
if _iq is None:
# If the expected Stanza would have arrived, ProcessNonBlocking
diff --git a/src/common/xmpp/transports_nb.py b/src/common/xmpp/transports_nb.py
index e23348bba..704cad170 100644
--- a/src/common/xmpp/transports_nb.py
+++ b/src/common/xmpp/transports_nb.py
@@ -645,44 +645,44 @@ class NonBlockingHTTP(NonBlockingTCP):
if self.get_state() == PROXY_CONNECTING:
NonBlockingTCP._on_receive(self, data)
return
- if not self.recvbuff:
- # recvbuff empty - fresh HTTP message was received
- try:
- statusline, headers, self.recvbuff = self.parse_http_message(data)
- except ValueError:
- self.disconnect()
- return
- if statusline[1] != '200':
- log.error('HTTP Error: %s %s' % (statusline[1], statusline[2]))
- self.disconnect()
- return
- self.expected_length = int(headers['Content-Length'])
- if 'Connection' in headers and headers['Connection'].strip()=='close':
- self.close_current_connection = True
- else:
- #sth in recvbuff - append currently received data to HTTP msg in buffer
- self.recvbuff = '%s%s' % (self.recvbuff, data)
- if self.expected_length > len(self.recvbuff):
+ # append currently received data to HTTP msg in buffer
+ self.recvbuff = '%s%s' % (self.recvbuff or '', data)
+ statusline, headers, httpbody, buffer_rest = self.parse_http_message(
+ self.recvbuff)
+
+ if not (statusline and headers and httpbody):
+ log.debug('Received incomplete HTTP response')
+ return
+
+ if statusline[1] != '200':
+ log.error('HTTP Error: %s %s' % (statusline[1], statusline[2]))
+ self.disconnect()
+ return
+ self.expected_length = int(headers['Content-Length'])
+ if 'Connection' in headers and headers['Connection'].strip()=='close':
+ self.close_current_connection = True
+
+ if self.expected_length > len(httpbody):
# If we haven't received the whole HTTP mess yet, let's end the thread.
# It will be finnished from one of following recvs on plugged socket.
log.info('not enough bytes in HTTP response - %d expected, %d got' %
(self.expected_length, len(self.recvbuff)))
- return
+ else:
+ # First part of buffer has been extraced and is going to be handled,
+ # remove it from buffer
+ self.recvbuff = buffer_rest
- # everything was received
- httpbody = self.recvbuff
+ # everything was received
+ self.expected_length = 0
- self.recvbuff = ''
- self.expected_length = 0
-
- if not self.http_persistent or self.close_current_connection:
- # not-persistent connections disconnect after response
- self.disconnect(do_callback=False)
- self.close_current_connection = False
- self.last_recv_time = time.time()
- self.on_receive(data=httpbody, socket=self)
- self.on_http_request_possible()
+ if not self.http_persistent or self.close_current_connection:
+ # not-persistent connections disconnect after response
+ self.disconnect(do_callback=False)
+ self.close_current_connection = False
+ self.last_recv_time = time.time()
+ self.on_receive(data=httpbody, socket=self)
+ self.on_http_request_possible()
def build_http_message(self, httpbody, method='POST'):
'''
@@ -707,7 +707,7 @@ class NonBlockingHTTP(NonBlockingTCP):
headers.append('Connection: Keep-Alive')
headers.append('\r\n')
headers = '\r\n'.join(headers)
- return('%s%s\r\n' % (headers, httpbody))
+ return('%s%s' % (headers, httpbody))
def parse_http_message(self, message):
'''
@@ -716,20 +716,27 @@ class NonBlockingHTTP(NonBlockingTCP):
headers - dictionary of headers e.g. {'Content-Length': '604',
'Content-Type': 'text/xml; charset=utf-8'},
httpbody - string with http body)
+ http_rest - what is left in the message after a full HTTP header + body
'''
message = message.replace('\r','')
- # Remove latest \n
- if message.endswith('\n'):
- message = message[:-1]
- (header, httpbody) = message.split('\n\n', 1)
- header = header.split('\n')
- statusline = header[0].split(' ', 2)
- header = header[1:]
- headers = {}
- for dummy in header:
- row = dummy.split(' ', 1)
- headers[row[0][:-1]] = row[1]
- return (statusline, headers, httpbody)
+ splitted = message.split('\n\n')
+ if len(splitted) < 2:
+ # no complete http message. Keep filling the buffer until we find one
+ buffer_rest = message
+ return ('', '', '', buffer_rest)
+ else:
+ (header, httpbody) = splitted[:2]
+ if httpbody.endswith('\n'):
+ httpbody = httpbody[:-1]
+ buffer_rest = "\n\n".join(splitted[2:])
+ header = header.split('\n')
+ statusline = header[0].split(' ', 2)
+ header = header[1:]
+ headers = {}
+ for dummy in header:
+ row = dummy.split(' ', 1)
+ headers[row[0][:-1]] = row[1]
+ return (statusline, headers, httpbody, buffer_rest)
class NonBlockingHTTPBOSH(NonBlockingHTTP):
diff --git a/src/common/zeroconf/client_zeroconf.py b/src/common/zeroconf/client_zeroconf.py
index d9158c568..730eb3ec3 100644
--- a/src/common/zeroconf/client_zeroconf.py
+++ b/src/common/zeroconf/client_zeroconf.py
@@ -494,7 +494,7 @@ class P2PConnection(IdleObject, PlugIn):
self.disconnect()
return True
- def disconnect(self):
+ def disconnect(self, message=''):
''' Closes the socket. '''
gajim.idlequeue.remove_timeout(self.fd)
gajim.idlequeue.unplug_idle(self.fd)
diff --git a/src/gui_interface.py b/src/gui_interface.py
index 0898ae39f..812aba08a 100644
--- a/src/gui_interface.py
+++ b/src/gui_interface.py
@@ -2145,7 +2145,7 @@ class Interface:
family = gajim.contacts.get_metacontacts_family(account, jid)
if family:
nearby_family, bb_jid, bb_account = \
- self.roster._get_nearby_family_and_big_brother(family, account)
+ gajim.contacts.get_nearby_family_and_big_brother(family, account)
else:
bb_jid, bb_account = jid, account
self.roster.select_contact(bb_jid, bb_account)
diff --git a/src/roster_window.py b/src/roster_window.py
index 2493f4dba..4ea9d884a 100644
--- a/src/roster_window.py
+++ b/src/roster_window.py
@@ -604,29 +604,7 @@ class RosterWindow:
big_brother_account=big_brother_account)
def _get_nearby_family_and_big_brother(self, family, account):
- '''Return the nearby family and its Big Brother
-
- Nearby family is the part of the family that is grouped with the metacontact.
- A metacontact may be over different accounts. If regroup is s False the
- given family is split account wise.
-
- (nearby_family, big_brother_jid, big_brother_account)
- '''
- if self.regroup:
- # group all together
- nearby_family = family
- else:
- # we want one nearby_family per account
- nearby_family = [data for data in family
- if account == data['account']]
-
- big_brother_data = gajim.contacts.get_metacontacts_big_brother(
- nearby_family)
- big_brother_jid = big_brother_data['jid']
- big_brother_account = big_brother_data['account']
-
- return (nearby_family, big_brother_jid, big_brother_account)
-
+ return gajim.contacts.get_nearby_family_and_big_brother(family, account)
def _add_self_contact(self, account):
'''Add account's SelfContact to roster and draw it and the account.
@@ -649,10 +627,8 @@ class RosterWindow:
return contact
-
def redraw_metacontacts(self, account):
- for tag in gajim.contacts.get_metacontacts_tags(account):
- family = gajim.contacts.get_metacontacts_family_from_tag(account, tag)
+ for family in gajim.contacts.iter_metacontacts_families(account):
self._recalibrate_metacontact_family(family, account)
def add_contact(self, jid, account):
diff --git a/src/session.py b/src/session.py
index 52f7b6045..04f9241eb 100644
--- a/src/session.py
+++ b/src/session.py
@@ -382,7 +382,7 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
family = gajim.contacts.get_metacontacts_family(self.conn.name, jid)
if family:
nearby_family, bb_jid, bb_account = \
- gajim.interface.roster._get_nearby_family_and_big_brother(family,
+ gajim.contacts.get_nearby_family_and_big_brother(family,
self.conn.name)
else:
bb_jid, bb_account = jid, self.conn.name
diff --git a/test/integration/test_xmpp_transports_nb.py b/test/integration/test_xmpp_transports_nb.py
index f6cbab510..6e56ddf94 100644
--- a/test/integration/test_xmpp_transports_nb.py
+++ b/test/integration/test_xmpp_transports_nb.py
@@ -227,9 +227,10 @@ class TestNonBlockingHTTP(AbstractTransportTest):
data = "