Merge changes from default branch into refactoring branch

This commit is contained in:
Stephan Erb 2009-11-13 11:55:48 +01:00
commit 01553e53c2
8 changed files with 114 additions and 106 deletions

View File

@ -581,11 +581,10 @@ class MetacontactManager():
#FIXME: can this append ? #FIXME: can this append ?
assert False assert False
def get_metacontacts_tags(self, account): def iter_metacontacts_families(self, account):
'''return a list of tags for a given account''' for tag in self._metacontacts_tags[account]:
if not account in self._metacontacts_tags: family = self._get_metacontacts_family_from_tag(account, tag)
return [] yield family
return self._metacontacts_tags[account].keys()
def _get_metacontacts_tag(self, account, jid): def _get_metacontacts_tag(self, account, jid):
'''Returns the tag of a jid''' '''Returns the tag of a jid'''
@ -643,7 +642,7 @@ class MetacontactManager():
tag = self._get_metacontacts_tag(account, jid) tag = self._get_metacontacts_tag(account, jid)
if not tag: if not tag:
return False 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 return len(meta_jids) > 1 or len(meta_jids[account]) > 1
def is_big_brother(self, account, jid, accounts): def is_big_brother(self, account, jid, accounts):
@ -651,12 +650,12 @@ class MetacontactManager():
if family: if family:
nearby_family = [data for data in family nearby_family = [data for data in family
if account in accounts] 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: if bb_data['jid'] == jid and bb_data['account'] == account:
return True return True
return False 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],.}''' '''Returns all jid for the given tag in the form {acct: [jid1, jid2],.}'''
answers = {} answers = {}
for account in self._metacontacts_tags: for account in self._metacontacts_tags:
@ -673,9 +672,9 @@ class MetacontactManager():
[{'account': acct, 'jid': jid, 'order': order}, ] [{'account': acct, 'jid': jid, 'order': order}, ]
'order' is optional''' 'order' is optional'''
tag = self._get_metacontacts_tag(account, jid) 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: if not tag:
return [] return []
answers = [] answers = []
@ -765,8 +764,30 @@ class MetacontactManager():
if account2 > account1: if account2 > account1:
return -1 return -1
return 0 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 '''which of the family will be the big brother under wich all
others will be ?''' others will be ?'''
family.sort(cmp=self._compare_metacontacts) family.sort(cmp=self._compare_metacontacts)

View File

@ -462,7 +462,10 @@ class XMPPDispatcher(PlugIn):
# we have released dispatcher, so self._owner has no methods # we have released dispatcher, so self._owner has no methods
if not res: if not res:
return 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(): for (_id, _iq) in self._expected.items():
if _iq is None: if _iq is None:
# If the expected Stanza would have arrived, ProcessNonBlocking # If the expected Stanza would have arrived, ProcessNonBlocking

View File

@ -645,44 +645,44 @@ class NonBlockingHTTP(NonBlockingTCP):
if self.get_state() == PROXY_CONNECTING: if self.get_state() == PROXY_CONNECTING:
NonBlockingTCP._on_receive(self, data) NonBlockingTCP._on_receive(self, data)
return 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. # 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. # It will be finnished from one of following recvs on plugged socket.
log.info('not enough bytes in HTTP response - %d expected, %d got' % log.info('not enough bytes in HTTP response - %d expected, %d got' %
(self.expected_length, len(self.recvbuff))) (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 # everything was received
httpbody = self.recvbuff self.expected_length = 0
self.recvbuff = '' if not self.http_persistent or self.close_current_connection:
self.expected_length = 0 # not-persistent connections disconnect after response
self.disconnect(do_callback=False)
if not self.http_persistent or self.close_current_connection: self.close_current_connection = False
# not-persistent connections disconnect after response self.last_recv_time = time.time()
self.disconnect(do_callback=False) self.on_receive(data=httpbody, socket=self)
self.close_current_connection = False self.on_http_request_possible()
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'): def build_http_message(self, httpbody, method='POST'):
''' '''
@ -707,7 +707,7 @@ class NonBlockingHTTP(NonBlockingTCP):
headers.append('Connection: Keep-Alive') headers.append('Connection: Keep-Alive')
headers.append('\r\n') headers.append('\r\n')
headers = '\r\n'.join(headers) headers = '\r\n'.join(headers)
return('%s%s\r\n' % (headers, httpbody)) return('%s%s' % (headers, httpbody))
def parse_http_message(self, message): def parse_http_message(self, message):
''' '''
@ -716,20 +716,27 @@ class NonBlockingHTTP(NonBlockingTCP):
headers - dictionary of headers e.g. {'Content-Length': '604', headers - dictionary of headers e.g. {'Content-Length': '604',
'Content-Type': 'text/xml; charset=utf-8'}, 'Content-Type': 'text/xml; charset=utf-8'},
httpbody - string with http body) httpbody - string with http body)
http_rest - what is left in the message after a full HTTP header + body
''' '''
message = message.replace('\r','') message = message.replace('\r','')
# Remove latest \n splitted = message.split('\n\n')
if message.endswith('\n'): if len(splitted) < 2:
message = message[:-1] # no complete http message. Keep filling the buffer until we find one
(header, httpbody) = message.split('\n\n', 1) buffer_rest = message
header = header.split('\n') return ('', '', '', buffer_rest)
statusline = header[0].split(' ', 2) else:
header = header[1:] (header, httpbody) = splitted[:2]
headers = {} if httpbody.endswith('\n'):
for dummy in header: httpbody = httpbody[:-1]
row = dummy.split(' ', 1) buffer_rest = "\n\n".join(splitted[2:])
headers[row[0][:-1]] = row[1] header = header.split('\n')
return (statusline, headers, httpbody) 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): class NonBlockingHTTPBOSH(NonBlockingHTTP):

View File

@ -494,7 +494,7 @@ class P2PConnection(IdleObject, PlugIn):
self.disconnect() self.disconnect()
return True return True
def disconnect(self): def disconnect(self, message=''):
''' Closes the socket. ''' ''' Closes the socket. '''
gajim.idlequeue.remove_timeout(self.fd) gajim.idlequeue.remove_timeout(self.fd)
gajim.idlequeue.unplug_idle(self.fd) gajim.idlequeue.unplug_idle(self.fd)

View File

@ -2145,7 +2145,7 @@ class Interface:
family = gajim.contacts.get_metacontacts_family(account, jid) family = gajim.contacts.get_metacontacts_family(account, jid)
if family: if family:
nearby_family, bb_jid, bb_account = \ 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: else:
bb_jid, bb_account = jid, account bb_jid, bb_account = jid, account
self.roster.select_contact(bb_jid, bb_account) self.roster.select_contact(bb_jid, bb_account)

View File

@ -604,29 +604,7 @@ class RosterWindow:
big_brother_account=big_brother_account) big_brother_account=big_brother_account)
def _get_nearby_family_and_big_brother(self, family, account): def _get_nearby_family_and_big_brother(self, family, account):
'''Return the nearby family and its Big Brother return gajim.contacts.get_nearby_family_and_big_brother(family, account)
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)
def _add_self_contact(self, account): def _add_self_contact(self, account):
'''Add account's SelfContact to roster and draw it and the account. '''Add account's SelfContact to roster and draw it and the account.
@ -649,10 +627,8 @@ class RosterWindow:
return contact return contact
def redraw_metacontacts(self, account): def redraw_metacontacts(self, account):
for tag in gajim.contacts.get_metacontacts_tags(account): for family in gajim.contacts.iter_metacontacts_families(account):
family = gajim.contacts.get_metacontacts_family_from_tag(account, tag)
self._recalibrate_metacontact_family(family, account) self._recalibrate_metacontact_family(family, account)
def add_contact(self, jid, account): def add_contact(self, jid, account):

View File

@ -382,7 +382,7 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
family = gajim.contacts.get_metacontacts_family(self.conn.name, jid) family = gajim.contacts.get_metacontacts_family(self.conn.name, jid)
if family: if family:
nearby_family, bb_jid, bb_account = \ 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) self.conn.name)
else: else:
bb_jid, bb_account = jid, self.conn.name bb_jid, bb_account = jid, self.conn.name

View File

@ -227,9 +227,10 @@ class TestNonBlockingHTTP(AbstractTransportTest):
data = "<test>Please don't fail!</test>" data = "<test>Please don't fail!</test>"
http_message = transport.build_http_message(data) http_message = transport.build_http_message(data)
statusline, headers, http_body = transport.parse_http_message( statusline, headers, http_body, buffer_rest = transport.parse_http_message(
http_message) http_message)
self.assertFalse(bool(buffer_rest))
self.assertTrue(statusline and isinstance(statusline, list)) self.assertTrue(statusline and isinstance(statusline, list))
self.assertTrue(headers and isinstance(headers, dict)) self.assertTrue(headers and isinstance(headers, dict))
self.assertEqual(data, http_body, msg='Input and output are different') self.assertEqual(data, http_body, msg='Input and output are different')
@ -250,26 +251,26 @@ class TestNonBlockingHTTP(AbstractTransportTest):
transport._on_receive(message) transport._on_receive(message)
self.assertTrue(self.have_received_expected(), msg='Failed: In one go') self.assertTrue(self.have_received_expected(), msg='Failed: In one go')
# FIXME: Not yet implemented. def test_receive_http_message_in_chunks(self):
# def test_receive_http_message_in_chunks(self): ''' Let _on_receive handle some chunked http messages '''
# ''' Let _on_receive handle some chunked http messages ''' transport = self._get_transport(self.bosh_http_dict)
# transport = self._get_transport(self.bosh_http_dict)
# header = ("HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset=utf-8\r\n" +
# header = ("HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset=utf-8\r\n" + "Content-Length: 88\r\n\r\n")
# "Content-Length: 88\r\n\r\n") payload = "<test>Please don't fail!</test>"
# payload = "<test>Please don't fail!</test>" body = "<body xmlns='http://jabber.org/protocol/httpbind'>%s</body>" \
# body = "<body xmlns='http://jabber.org/protocol/httpbind'>%s</body>" \ % payload
# % payload message = "%s%s" % (header, body)
# message = "%s%s" % (header, body)
# chunk1, chunk2, chunk3, chunk4 = message[:20], message[20:73], \
# chunk1, chunk2, chunk3 = message[:20], message[20:73], message[73:] message[73:85], message[85:]
# nextmessage_chunk = "\r\n\r\nHTTP/1.1 200 OK\r\nContent-Type: text/x" nextmessage_chunk = "\r\n\r\nHTTP/1.1 200 OK\r\nContent-Type: text/x"
# chunks = (chunk1, chunk2, chunk3, nextmessage_chunk) chunks = (chunk1, chunk2, chunk3, chunk4, nextmessage_chunk)
#
# transport.onreceive(self.expect_receive(body, msg='Failed: In chunks')) transport.onreceive(self.expect_receive(body, msg='Failed: In chunks'))
# for chunk in chunks: for chunk in chunks:
# transport._on_receive(chunk) transport._on_receive(chunk)
# self.assertTrue(self.have_received_expected(), msg='Failed: In chunks') self.assertTrue(self.have_received_expected(), msg='Failed: In chunks')
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()