Merge changes from refactoring branch back to default

This commit is contained in:
Stephan Erb 2009-11-11 23:38:17 +01:00
commit 641947719f
23 changed files with 638 additions and 416 deletions

View File

@ -2774,7 +2774,7 @@ class ChatControl(ChatControlBase):
contact = gajim.contacts.get_contact_with_highest_priority( contact = gajim.contacts.get_contact_with_highest_priority(
self.account, self.contact.jid) self.account, self.contact.jid)
if isinstance(contact, GC_Contact): if isinstance(contact, GC_Contact):
contact = gajim.contacts.contact_from_gc_contact(contact) contact = contact.as_contact()
if contact: if contact:
self.contact = contact self.contact = contact
self.draw_banner() self.draw_banner()

32
src/common/account.py Normal file
View File

@ -0,0 +1,32 @@
# -*- coding:utf-8 -*-
## src/common/contacts.py
##
## Copyright (C) 2009 Stephan Erb <steve-e AT h3c.de>
##
## This file is part of Gajim.
##
## Gajim is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published
## by the Free Software Foundation; version 3 only.
##
## Gajim is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
##
class Account(object):
def __init__(self, name, contacts, gc_contacts):
self.name = name
self.contacts = contacts
self.gc_contacts = gc_contacts
def __repr__(self):
return self.name
def __hash__(self):
return self.name.__hash__()

View File

@ -40,13 +40,34 @@ from common.xmpp import NS_XHTML_IM, NS_RECEIPTS, NS_ESESSION, NS_CHATSTATES
# Features where we cannot safely assume that the other side supports them # Features where we cannot safely assume that the other side supports them
FEATURE_BLACKLIST = [NS_CHATSTATES, NS_XHTML_IM, NS_RECEIPTS, NS_ESESSION] FEATURE_BLACKLIST = [NS_CHATSTATES, NS_XHTML_IM, NS_RECEIPTS, NS_ESESSION]
# Query entry status codes
NEW = 0
QUERIED = 1
CACHED = 2 # got the answer
################################################################################
### Public API of this module
################################################################################
capscache = None capscache = None
def initialize(logger): def initialize(logger):
''' Initializes the capscache global ''' ''' Initializes this module '''
global capscache global capscache
capscache = CapsCache(logger) capscache = CapsCache(logger)
def client_supports(client_caps, requested_feature):
lookup_item = client_caps.get_cache_lookup_strategy()
cache_item = lookup_item(capscache)
supported_features = cache_item.features
if requested_feature in supported_features:
return True
elif supported_features == [] and cache_item.status in (NEW, QUERIED):
# assume feature is supported, if we don't know yet, what the client
# is capable of
return requested_feature not in FEATURE_BLACKLIST
else:
return False
def compute_caps_hash(identities, features, dataforms=[], hash_method='sha-1'): def compute_caps_hash(identities, features, dataforms=[], hash_method='sha-1'):
'''Compute caps hash according to XEP-0115, V1.5 '''Compute caps hash according to XEP-0115, V1.5
@ -118,6 +139,10 @@ def compute_caps_hash(identities, features, dataforms=[], hash_method='sha-1'):
return base64.b64encode(hash_.digest()) return base64.b64encode(hash_.digest())
################################################################################
### Internal classes of this module
################################################################################
class AbstractClientCaps(object): class AbstractClientCaps(object):
''' '''
Base class representing a client and its capabilities as advertised by Base class representing a client and its capabilities as advertised by
@ -147,8 +172,8 @@ class AbstractClientCaps(object):
def _is_hash_valid(self, identities, features, dataforms): def _is_hash_valid(self, identities, features, dataforms):
''' To be implemented by subclassess ''' ''' To be implemented by subclassess '''
raise NotImplementedError() raise NotImplementedError()
class ClientCaps(AbstractClientCaps): class ClientCaps(AbstractClientCaps):
''' The current XEP-115 implementation ''' ''' The current XEP-115 implementation '''
@ -167,7 +192,7 @@ class ClientCaps(AbstractClientCaps):
computed_hash = compute_caps_hash(identities, features, computed_hash = compute_caps_hash(identities, features,
dataforms=dataforms, hash_method=self._hash_method) dataforms=dataforms, hash_method=self._hash_method)
return computed_hash == self._hash return computed_hash == self._hash
class OldClientCaps(AbstractClientCaps): class OldClientCaps(AbstractClientCaps):
''' Old XEP-115 implemtation. Kept around for background competability. ''' ''' Old XEP-115 implemtation. Kept around for background competability. '''
@ -183,7 +208,7 @@ class OldClientCaps(AbstractClientCaps):
def _is_hash_valid(self, identities, features, dataforms): def _is_hash_valid(self, identities, features, dataforms):
return True return True
class NullClientCaps(AbstractClientCaps): class NullClientCaps(AbstractClientCaps):
''' '''
@ -199,7 +224,7 @@ class NullClientCaps(AbstractClientCaps):
def _lookup_in_cache(self, caps_cache): def _lookup_in_cache(self, caps_cache):
# lookup something which does not exist to get a new CacheItem created # lookup something which does not exist to get a new CacheItem created
cache_item = caps_cache[('dummy', '')] cache_item = caps_cache[('dummy', '')]
assert cache_item.queried != 2 assert cache_item.status != CACHED
return cache_item return cache_item
def _discover(self, connection, jid): def _discover(self, connection, jid):
@ -236,12 +261,8 @@ class CapsCache(object):
self._identities = [] self._identities = []
self._logger = logger self._logger = logger
# not cached into db: self.status = NEW
# have we sent the query? self._recently_seen = False
# 0 == not queried
# 1 == queried
# 2 == got the answer
self.queried = 0
def _get_features(self): def _get_features(self):
return self._features return self._features
@ -283,19 +304,28 @@ class CapsCache(object):
self.features = features self.features = features
self._logger.add_caps_entry(self.hash_method, self.hash, self._logger.add_caps_entry(self.hash_method, self.hash,
identities, features) identities, features)
self.status = CACHED
def update_last_seen(self):
if not self._recently_seen:
self._recently_seen = True
self._logger.update_caps_time(self.hash_method, self.hash)
self.__CacheItem = CacheItem self.__CacheItem = CacheItem
self.logger = logger self.logger = logger
def initialize_from_db(self): def initialize_from_db(self):
# get data from logger... self._remove_outdated_caps()
if self.logger is not None: for hash_method, hash_, identities, features in \
for hash_method, hash_, identities, features in \ self.logger.iter_caps_data():
self.logger.iter_caps_data(): x = self[(hash_method, hash_)]
x = self[(hash_method, hash_)] x.identities = identities
x.identities = identities x.features = features
x.features = features x.status = CACHED
x.queried = 2
def _remove_outdated_caps(self):
'''Removes outdated values from the db'''
self.logger.clean_caps_table()
def __getitem__(self, caps): def __getitem__(self, caps):
if caps in self.__cache: if caps in self.__cache:
@ -315,13 +345,18 @@ class CapsCache(object):
lookup_cache_item = client_caps.get_cache_lookup_strategy() lookup_cache_item = client_caps.get_cache_lookup_strategy()
q = lookup_cache_item(self) q = lookup_cache_item(self)
if q.queried == 0: if q.status == NEW:
# do query for bare node+hash pair # do query for bare node+hash pair
# this will create proper object # this will create proper object
q.queried = 1 q.status = QUERIED
discover = client_caps.get_discover_strategy() discover = client_caps.get_discover_strategy()
discover(connection, jid) discover(connection, jid)
else:
q.update_last_seen()
################################################################################
### Caps network coding
################################################################################
class ConnectionCaps(object): class ConnectionCaps(object):
''' '''
@ -366,7 +401,7 @@ class ConnectionCaps(object):
client_caps = OldClientCaps(caps_hash, node) client_caps = OldClientCaps(caps_hash, node)
else: else:
client_caps = ClientCaps(caps_hash, node, hash_method) client_caps = ClientCaps(caps_hash, node, hash_method)
capscache.query_client_of_jid_if_unknown(self, jid, client_caps) capscache.query_client_of_jid_if_unknown(self, jid, client_caps)
contact.client_caps = client_caps contact.client_caps = client_caps
@ -384,7 +419,7 @@ class ConnectionCaps(object):
lookup = contact.client_caps.get_cache_lookup_strategy() lookup = contact.client_caps.get_cache_lookup_strategy()
cache_item = lookup(capscache) cache_item = lookup(capscache)
if cache_item.queried == 2: if cache_item.status == CACHED:
return return
else: else:
validate = contact.client_caps.get_hash_validation_strategy() validate = contact.client_caps.get_hash_validation_strategy()

View File

@ -91,7 +91,8 @@ def create_log_db():
CREATE TABLE caps_cache ( CREATE TABLE caps_cache (
hash_method TEXT, hash_method TEXT,
hash TEXT, hash TEXT,
data BLOB); data BLOB,
last_seen INTEGER);
CREATE TABLE rooms_last_message_time( CREATE TABLE rooms_last_message_time(
jid_id INTEGER PRIMARY KEY UNIQUE, jid_id INTEGER PRIMARY KEY UNIQUE,

View File

@ -2468,8 +2468,12 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
for sess in self.sessions[jid].values(): for sess in self.sessions[jid].values():
if not sess.received_thread_id: if not sess.received_thread_id:
contact = gajim.contacts.get_contact(self.name, jid) contact = gajim.contacts.get_contact(self.name, jid)
# FIXME: I don't know if this is the correct behavior here.
session_supported = contact.supports(common.xmpp.NS_SSN) or \ # Anyway, it is the old behavior when we assumed that
# not-existing contacts don't support anything
contact_exists = bool(contact)
session_supported = contact_exists and \
contact.supports(common.xmpp.NS_SSN) or \
contact.supports(common.xmpp.NS_ESESSION) contact.supports(common.xmpp.NS_ESESSION)
if session_supported: if session_supported:
sess.terminate() sess.terminate()

View File

@ -29,18 +29,24 @@
## ##
import common.gajim import common.gajim
import caps
from account import Account
class XMPPEntity(object):
from common import caps '''Base representation of entities in XMPP'''
class CommonContact(object):
def __init__(self, jid, resource, show, status, name, our_chatstate, def __init__(self, jid, account, resource):
composing_xep, chatstate, client_caps=None):
self.jid = jid self.jid = jid
self.resource = resource self.resource = resource
self.account = account
class CommonContact(XMPPEntity):
def __init__(self, jid, account, resource, show, status, name, our_chatstate,
composing_xep, chatstate, client_caps=None):
XMPPEntity.__init__(self, jid, account, resource)
self.show = show self.show = show
self.status = status self.status = status
self.name = name self.name = name
@ -80,35 +86,21 @@ class CommonContact(object):
# return caps for a contact that has no resources left. # return caps for a contact that has no resources left.
return False return False
else: else:
return self._client_supports(requested_feature) return caps.client_supports(self.client_caps, requested_feature)
def _client_supports(self, requested_feature):
lookup_item = self.client_caps.get_cache_lookup_strategy()
cache_item = lookup_item(caps.capscache)
supported_features = cache_item.features
if requested_feature in supported_features:
return True
elif supported_features == [] and cache_item.queried in (0, 1):
# assume feature is supported, if we don't know yet, what the client
# is capable of
return requested_feature not in caps.FEATURE_BLACKLIST
else:
return False
class Contact(CommonContact): class Contact(CommonContact):
'''Information concerning each contact''' '''Information concerning each contact'''
def __init__(self, jid='', name='', groups=[], show='', status='', sub='', def __init__(self, jid, account, name='', groups=[], show='', status='', sub='',
ask='', resource='', priority=0, keyID='', client_caps=None, ask='', resource='', priority=0, keyID='', client_caps=None,
our_chatstate=None, chatstate=None, last_status_time=None, msg_id = None, our_chatstate=None, chatstate=None, last_status_time=None, msg_id = None,
composing_xep=None, mood={}, tune={}, activity={}): composing_xep=None, mood={}, tune={}, activity={}):
CommonContact.__init__(self, jid, resource, show, status, name, CommonContact.__init__(self, jid, account, resource, show, status, name,
our_chatstate, composing_xep, chatstate, client_caps=client_caps) our_chatstate, composing_xep, chatstate, client_caps=client_caps)
self.contact_name = '' # nick choosen by contact self.contact_name = '' # nick choosen by contact
self.groups = groups self.groups = [i for i in set(groups)] # filter duplicate values
self.sub = sub self.sub = sub
self.ask = ask self.ask = ask
@ -184,11 +176,11 @@ class Contact(CommonContact):
class GC_Contact(CommonContact): class GC_Contact(CommonContact):
'''Information concerning each groupchat contact''' '''Information concerning each groupchat contact'''
def __init__(self, room_jid='', name='', show='', status='', role='', def __init__(self, room_jid, account, name='', show='', status='', role='',
affiliation='', jid='', resource='', our_chatstate=None, affiliation='', jid='', resource='', our_chatstate=None,
composing_xep=None, chatstate=None): composing_xep=None, chatstate=None):
CommonContact.__init__(self, jid, resource, show, status, name, CommonContact.__init__(self, jid, account, resource, show, status, name,
our_chatstate, composing_xep, chatstate) our_chatstate, composing_xep, chatstate)
self.room_jid = room_jid self.room_jid = room_jid
@ -201,153 +193,112 @@ class GC_Contact(CommonContact):
def get_shown_name(self): def get_shown_name(self):
return self.name return self.name
def as_contact(self):
'''Create a Contact instance from this GC_Contact instance'''
return Contact(jid=self.get_full_jid(), account=self.account,
resource=self.resource, name=self.name, groups=[], show=self.show,
status=self.status, sub='none', client_caps=self.client_caps)
class Contacts: class Contacts:
'''Information concerning all contacts and groupchat contacts''' '''Information concerning all contacts and groupchat contacts'''
def __init__(self): def __init__(self):
self._contacts = {} # list of contacts {acct: {jid1: [C1, C2]}, } one Contact per resource
self._gc_contacts = {} # list of contacts that are in gc {acct: {room_jid: {nick: C}}} self._metacontact_manager = MetacontactManager(self)
self._accounts = {}
def change_account_name(self, old_name, new_name):
self._accounts[new_name] = self._accounts[old_name]
del self._accounts[old_name]
self._metacontact_manager.change_account_name(old_name, new_name)
# For meta contacts: def add_account(self, account_name):
self._metacontacts_tags = {} self._accounts[account_name] = Account(account_name,
Contacts_New(), GC_Contacts())
def change_account_name(self, old_name, new_name): self._metacontact_manager.add_account(account_name)
self._contacts[new_name] = self._contacts[old_name]
self._gc_contacts[new_name] = self._gc_contacts[old_name]
self._metacontacts_tags[new_name] = self._metacontacts_tags[old_name]
del self._contacts[old_name]
del self._gc_contacts[old_name]
del self._metacontacts_tags[old_name]
def change_contact_jid(self, old_jid, new_jid, account):
if account not in self._contacts:
return
if old_jid not in self._contacts[account]:
return
self._contacts[account][new_jid] = []
for _contact in self._contacts[account][old_jid]:
_contact.jid = new_jid
self._contacts[account][new_jid].append(_contact)
del self._contacts[account][old_jid]
def add_account(self, account):
self._contacts[account] = {}
self._gc_contacts[account] = {}
if account not in self._metacontacts_tags:
self._metacontacts_tags[account] = {}
def get_accounts(self): def get_accounts(self):
return self._contacts.keys() return self._accounts.keys()
def remove_account(self, account): def remove_account(self, account):
del self._contacts[account] del self._accounts[account]
del self._gc_contacts[account] self._metacontact_manager.remove_account(account)
del self._metacontacts_tags[account]
def create_contact(self, jid='', name='', groups=[], show='', status='', def create_contact(self, jid, account, name='', groups=[], show='', status='',
sub='', ask='', resource='', priority=0, keyID='', client_caps=None, sub='', ask='', resource='', priority=0, keyID='', client_caps=None,
our_chatstate=None, chatstate=None, last_status_time=None, our_chatstate=None, chatstate=None, last_status_time=None,
composing_xep=None, mood={}, tune={}, activity={}): composing_xep=None, mood={}, tune={}, activity={}):
account = self._accounts.get(account, account) # Use Account object if available
# We don't want duplicated group values return Contact(jid=jid, account=account, name=name, groups=groups,
groups_unique = [] show=show, status=status, sub=sub, ask=ask, resource=resource, priority=priority,
for group in groups:
if group not in groups_unique:
groups_unique.append(group)
return Contact(jid=jid, name=name, groups=groups_unique, show=show,
status=status, sub=sub, ask=ask, resource=resource, priority=priority,
keyID=keyID, client_caps=client_caps, our_chatstate=our_chatstate, keyID=keyID, client_caps=client_caps, our_chatstate=our_chatstate,
chatstate=chatstate, last_status_time=last_status_time, chatstate=chatstate, last_status_time=last_status_time,
composing_xep=composing_xep, mood=mood, tune=tune, activity=activity) composing_xep=composing_xep, mood=mood, tune=tune, activity=activity)
def create_self_contact(self, jid, account, resource, show, status, priority, keyID=''):
conn = common.gajim.connections[account]
nick = common.gajim.nicks[account]
account = self._accounts.get(account, account) # Use Account object if available
return self.create_contact(jid=jid, account=account,
name=nick, groups=['self_contact'], show=show, status=status,
sub='both', ask='none', priority=priority, keyID=keyID,
resource=resource, mood=conn.mood, tune=conn.tune,
activity=conn.activity)
def create_not_in_roster_contact(self, jid, account, resource='', name='', keyID=''):
account = self._accounts.get(account, account) # Use Account object if available
return self.create_contact(jid=jid, account=account, resource=resource,
name=name, groups=[_('Not in Roster')], show='not in roster',
status='', sub='none', keyID=keyID)
def copy_contact(self, contact): def copy_contact(self, contact):
return self.create_contact(jid=contact.jid, name=contact.name, return self.create_contact(jid=contact.jid, account=contact.account,
groups=contact.groups, show=contact.show, status=contact.status, name=contact.name, groups=contact.groups, show=contact.show, status=contact.status,
sub=contact.sub, ask=contact.ask, resource=contact.resource, sub=contact.sub, ask=contact.ask, resource=contact.resource,
priority=contact.priority, keyID=contact.keyID, priority=contact.priority, keyID=contact.keyID,
client_caps=contact.client_caps, our_chatstate=contact.our_chatstate, client_caps=contact.client_caps, our_chatstate=contact.our_chatstate,
chatstate=contact.chatstate, last_status_time=contact.last_status_time) chatstate=contact.chatstate, last_status_time=contact.last_status_time)
def add_contact(self, account, contact): def add_contact(self, account, contact):
# No such account before ? if account not in self._accounts:
if account not in self._contacts: self.add_account(account)
self._contacts[account] = {contact.jid : [contact]} return self._accounts[account].contacts.add_contact(contact)
return
# No such jid before ?
if contact.jid not in self._contacts[account]:
self._contacts[account][contact.jid] = [contact]
return
contacts = self._contacts[account][contact.jid]
# We had only one that was offline, remove it
if len(contacts) == 1 and contacts[0].show == 'offline':
# Do not use self.remove_contact: it deteles
# self._contacts[account][contact.jid]
contacts.remove(contacts[0])
# If same JID with same resource already exists, use the new one
for c in contacts:
if c.resource == contact.resource:
self.remove_contact(account, c)
break
contacts.append(contact)
def remove_contact(self, account, contact): def remove_contact(self, account, contact):
if account not in self._contacts: if account not in self._accounts:
return return
if contact.jid not in self._contacts[account]: return self._accounts[account].contacts.remove_contact(contact)
return
if contact in self._contacts[account][contact.jid]:
self._contacts[account][contact.jid].remove(contact)
if len(self._contacts[account][contact.jid]) == 0:
del self._contacts[account][contact.jid]
def clear_contacts(self, account):
self._contacts[account] = {}
def remove_jid(self, account, jid, remove_meta=True): def remove_jid(self, account, jid, remove_meta=True):
'''Removes all contacts for a given jid''' self._accounts[account].contacts.remove_jid(jid)
if account not in self._contacts:
return
if jid not in self._contacts[account]:
return
del self._contacts[account][jid]
if remove_meta: if remove_meta:
# remove metacontacts info self._metacontact_manager.remove_metacontact(account, jid)
self.remove_metacontact(account, jid)
def get_contacts(self, account, jid): def get_contacts(self, account, jid):
'''Returns the list of contact instances for this jid.''' return self._accounts[account].contacts.get_contacts(jid)
if jid in self._contacts[account]:
return self._contacts[account][jid]
else:
return []
def get_contact(self, account, jid, resource=None): def get_contact(self, account, jid, resource=None):
### WARNING ### return self._accounts[account].contacts.get_contact(jid, resource=resource)
# This function returns a *RANDOM* resource if resource = None!
# Do *NOT* use if you need to get the contact to which you
# send a message for example, as a bare JID in Jabber means
# highest available resource, which this function ignores!
'''Returns the contact instance for the given resource if it's given else
the first contact is no resource is given or None if there is not'''
if jid in self._contacts[account]:
if not resource:
return self._contacts[account][jid][0]
for c in self._contacts[account][jid]:
if c.resource == resource:
return c
return None
def iter_contacts(self, account): def iter_contacts(self, account):
if account in self._contacts: for contact in self._accounts[account].contacts.iter_contacts():
for jid in self._contacts[account].keys(): yield contact
for contact in self._contacts[account][jid][:]:
yield contact
def get_contact_from_full_jid(self, account, fjid): def get_contact_from_full_jid(self, account, fjid):
''' Get Contact object for specific resource of given jid''' return self._accounts[account].contacts.get_contact_from_full_jid(fjid)
barejid, resource = common.gajim.get_room_and_nick_from_fjid(fjid)
return self.get_contact(account, barejid, resource) def get_first_contact_from_jid(self, account, jid):
return self._accounts[account].contacts.get_first_contact_from_jid(jid)
def get_contacts_from_group(self, account, group):
return self._accounts[account].contacts.get_contacts_from_group(group)
def get_jid_list(self, account):
return self._accounts[account].contacts.get_jid_list()
def change_contact_jid(self, old_jid, new_jid, account):
return self._accounts[account].change_contact_jid(old_jid, new_jid)
def get_highest_prio_contact_from_contacts(self, contacts): def get_highest_prio_contact_from_contacts(self, contacts):
if not contacts: if not contacts:
@ -366,21 +317,7 @@ class Contacts:
contact = self.get_gc_contact(account, room, nick) contact = self.get_gc_contact(account, room, nick)
return contact return contact
return self.get_highest_prio_contact_from_contacts(contacts) return self.get_highest_prio_contact_from_contacts(contacts)
def get_first_contact_from_jid(self, account, jid):
if jid in self._contacts[account]:
return self._contacts[account][jid][0]
return None
def get_contacts_from_group(self, account, group):
'''Returns all contacts in the given group'''
group_contacts = []
for jid in self._contacts[account]:
contacts = self.get_contacts(account, jid)
if group in contacts[0].groups:
group_contacts += contacts
return group_contacts
def get_nb_online_total_contacts(self, accounts=[], groups=[]): def get_nb_online_total_contacts(self, accounts=[], groups=[]):
'''Returns the number of online contacts and the total number of '''Returns the number of online contacts and the total number of
contacts''' contacts'''
@ -419,11 +356,227 @@ class Contacts:
nbr_total += 1 nbr_total += 1
return nbr_online, nbr_total return nbr_online, nbr_total
def is_pm_from_jid(self, account, jid):
'''Returns True if the given jid is a private message jid'''
if jid in self._contacts[account]:
return False
return True
def is_pm_from_contact(self, account, contact):
'''Returns True if the given contact is a private message contact'''
if isinstance(contact, Contact):
return False
return True
def __getattr__(self, attr_name):
# Only called if self has no attr_name
if hasattr(self._metacontact_manager, attr_name):
return getattr(self._metacontact_manager, attr_name)
else:
raise AttributeError(attr_name)
def create_gc_contact(self, room_jid, account, name='', show='', status='',
role='', affiliation='', jid='', resource=''):
account = self._accounts.get(account, account) # Use Account object if available
return GC_Contact(room_jid, account, name, show, status, role, affiliation, jid,
resource)
def add_gc_contact(self, account, gc_contact):
return self._accounts[account].gc_contacts.add_gc_contact(gc_contact)
def remove_gc_contact(self, account, gc_contact):
return self._accounts[account].gc_contacts.remove_gc_contact(gc_contact)
def remove_room(self, account, room_jid):
return self._accounts[account].gc_contacts.remove_room(room_jid)
def get_gc_list(self, account):
return self._accounts[account].gc_contacts.get_gc_list()
def get_nick_list(self, account, room_jid):
return self._accounts[account].gc_contacts.get_nick_list(room_jid)
def get_gc_contact(self, account, room_jid, nick):
return self._accounts[account].gc_contacts.get_gc_contact(room_jid, nick)
def get_nb_role_total_gc_contacts(self, account, room_jid, role):
return self._accounts[account].gc_contacts.get_nb_role_total_gc_contacts(room_jid, role)
class Contacts_New():
def __init__(self):
# list of contacts {jid1: [C1, C2]}, } one Contact per resource
self._contacts = {}
def add_contact(self, contact):
if contact.jid not in self._contacts:
self._contacts[contact.jid] = [contact]
return
contacts = self._contacts[contact.jid]
# We had only one that was offline, remove it
if len(contacts) == 1 and contacts[0].show == 'offline':
# Do not use self.remove_contact: it deteles
# self._contacts[account][contact.jid]
contacts.remove(contacts[0])
# If same JID with same resource already exists, use the new one
for c in contacts:
if c.resource == contact.resource:
self.remove_contact(c)
break
contacts.append(contact)
def remove_contact(self, contact):
if contact.jid not in self._contacts:
return
if contact in self._contacts[contact.jid]:
self._contacts[contact.jid].remove(contact)
if len(self._contacts[contact.jid]) == 0:
del self._contacts[contact.jid]
def remove_jid(self, jid):
'''Removes all contacts for a given jid'''
if jid not in self._contacts:
return
del self._contacts[jid]
def get_contacts(self, jid):
'''Returns the list of contact instances for this jid.'''
if jid in self._contacts:
return self._contacts[jid]
else:
return []
def get_contact(self, jid, resource=None):
### WARNING ###
# This function returns a *RANDOM* resource if resource = None!
# Do *NOT* use if you need to get the contact to which you
# send a message for example, as a bare JID in Jabber means
# highest available resource, which this function ignores!
'''Returns the contact instance for the given resource if it's given else
the first contact is no resource is given or None if there is not'''
if jid in self._contacts:
if not resource:
return self._contacts[jid][0]
for c in self._contacts[jid]:
if c.resource == resource:
return c
return None
def iter_contacts(self):
for jid in self._contacts.keys():
for contact in self._contacts[jid][:]:
yield contact
def get_jid_list(self):
return self._contacts.keys()
def get_contact_from_full_jid(self, fjid):
''' Get Contact object for specific resource of given jid'''
barejid, resource = common.gajim.get_room_and_nick_from_fjid(fjid)
return self.get_contact(barejid, resource)
def get_first_contact_from_jid(self, jid):
if jid in self._contacts:
return self._contacts[jid][0]
return None
def get_contacts_from_group(self, group):
'''Returns all contacts in the given group'''
group_contacts = []
for jid in self._contacts:
contacts = self.get_contacts(jid)
if group in contacts[0].groups:
group_contacts += contacts
return group_contacts
def change_contact_jid(self, old_jid, new_jid):
if old_jid not in self._contacts:
return
self._contacts[new_jid] = []
for _contact in self._contacts[old_jid]:
_contact.jid = new_jid
self._contacts[new_jid].append(_contact)
del self._contacts[old_jid]
class GC_Contacts():
def __init__(self):
# list of contacts that are in gc {room_jid: {nick: C}}}
self._rooms = {}
def add_gc_contact(self, gc_contact):
if gc_contact.room_jid not in self._rooms:
self._rooms[gc_contact.room_jid] = {gc_contact.name: gc_contact}
else:
self._rooms[gc_contact.room_jid][gc_contact.name] = gc_contact
def remove_gc_contact(self, gc_contact):
if gc_contact.room_jid not in self._rooms:
return
if gc_contact.name not in self._rooms[gc_contact.room_jid]:
return
del self._rooms[gc_contact.room_jid][gc_contact.name]
# It was the last nick in room ?
if not len(self._rooms[gc_contact.room_jid]):
del self._rooms[gc_contact.room_jid]
def remove_room(self, room_jid):
if room_jid not in self._rooms:
return
del self._rooms[room_jid]
def get_gc_list(self):
return self._rooms.keys()
def get_nick_list(self, room_jid):
gc_list = self.get_gc_list()
if not room_jid in gc_list:
return []
return self._rooms[room_jid].keys()
def get_gc_contact(self, room_jid, nick):
nick_list = self.get_nick_list(room_jid)
if not nick in nick_list:
return None
return self._rooms[room_jid][nick]
def get_nb_role_total_gc_contacts(self, room_jid, role):
'''Returns the number of group chat contacts for the given role and the
total number of group chat contacts'''
if room_jid not in self._rooms:
return 0, 0
nb_role = nb_total = 0
for nick in self._rooms[room_jid]:
if self._rooms[room_jid][nick].role == role:
nb_role += 1
nb_total += 1
return nb_role, nb_total
class MetacontactManager():
def __init__(self, contacts):
self._metacontacts_tags = {}
self._contacts = contacts
def change_account_name(self, old_name, new_name):
self._metacontacts_tags[new_name] = self._metacontacts_tags[old_name]
del self._metacontacts_tags[old_name]
def add_account(self, account):
if account not in self._metacontacts_tags:
self._metacontacts_tags[account] = {}
def remove_account(self, account):
del self._metacontacts_tags[account]
def define_metacontacts(self, account, tags_list): def define_metacontacts(self, account, tags_list):
self._metacontacts_tags[account] = tags_list self._metacontacts_tags[account] = tags_list
def get_new_metacontacts_tag(self, jid): def _get_new_metacontacts_tag(self, jid):
if not jid in self._metacontacts_tags.keys(): if not jid in self._metacontacts_tags:
return jid return jid
#FIXME: can this append ? #FIXME: can this append ?
assert False assert False
@ -434,7 +587,7 @@ class Contacts:
return [] return []
return self._metacontacts_tags[account].keys() 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'''
if not account in self._metacontacts_tags: if not account in self._metacontacts_tags:
return None return None
@ -445,19 +598,19 @@ class Contacts:
return None return None
def add_metacontact(self, brother_account, brother_jid, account, jid, order=None): def add_metacontact(self, brother_account, brother_jid, account, jid, order=None):
tag = self.get_metacontacts_tag(brother_account, brother_jid) tag = self._get_metacontacts_tag(brother_account, brother_jid)
if not tag: if not tag:
tag = self.get_new_metacontacts_tag(brother_jid) tag = self._get_new_metacontacts_tag(brother_jid)
self._metacontacts_tags[brother_account][tag] = [{'jid': brother_jid, self._metacontacts_tags[brother_account][tag] = [{'jid': brother_jid,
'tag': tag}] 'tag': tag}]
if brother_account != account: if brother_account != account:
common.gajim.connections[brother_account].store_metacontacts( common.gajim.connections[brother_account].store_metacontacts(
self._metacontacts_tags[brother_account]) self._metacontacts_tags[brother_account])
# be sure jid has no other tag # be sure jid has no other tag
old_tag = self.get_metacontacts_tag(account, jid) old_tag = self._get_metacontacts_tag(account, jid)
while old_tag: while old_tag:
self.remove_metacontact(account, jid) self.remove_metacontact(account, jid)
old_tag = self.get_metacontacts_tag(account, jid) old_tag = self._get_metacontacts_tag(account, jid)
if tag not in self._metacontacts_tags[account]: if tag not in self._metacontacts_tags[account]:
self._metacontacts_tags[account][tag] = [{'jid': jid, 'tag': tag}] self._metacontacts_tags[account][tag] = [{'jid': jid, 'tag': tag}]
else: else:
@ -471,6 +624,9 @@ class Contacts:
self._metacontacts_tags[account]) self._metacontacts_tags[account])
def remove_metacontact(self, account, jid): def remove_metacontact(self, account, jid):
if not account in self._metacontacts_tags:
return None
found = None found = None
for tag in self._metacontacts_tags[account]: for tag in self._metacontacts_tags[account]:
for data in self._metacontacts_tags[account][tag]: for data in self._metacontacts_tags[account][tag]:
@ -484,7 +640,7 @@ class Contacts:
break break
def has_brother(self, account, jid, accounts): def has_brother(self, account, jid, accounts):
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)
@ -516,7 +672,7 @@ class Contacts:
'''return the family of the given jid, including jid in the form: '''return the family of the given jid, including jid in the form:
[{'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):
@ -530,7 +686,7 @@ class Contacts:
answers.append(data) answers.append(data)
return answers return answers
def compare_metacontacts(self, data1, data2): def _compare_metacontacts(self, data1, data2):
'''compare 2 metacontacts. '''compare 2 metacontacts.
Data is {'jid': jid, 'account': account, 'order': order} Data is {'jid': jid, 'account': account, 'order': order}
order is optional''' order is optional'''
@ -538,8 +694,8 @@ class Contacts:
jid2 = data2['jid'] jid2 = data2['jid']
account1 = data1['account'] account1 = data1['account']
account2 = data2['account'] account2 = data2['account']
contact1 = self.get_contact_with_highest_priority(account1, jid1) contact1 = self._contacts.get_contact_with_highest_priority(account1, jid1)
contact2 = self.get_contact_with_highest_priority(account2, jid2) contact2 = self._contacts.get_contact_with_highest_priority(account2, jid2)
show_list = ['not in roster', 'error', 'offline', 'invisible', 'dnd', show_list = ['not in roster', 'error', 'offline', 'invisible', 'dnd',
'xa', 'away', 'chat', 'online', 'requested', 'message'] 'xa', 'away', 'chat', 'online', 'requested', 'message']
# contact can be null when a jid listed in the metacontact data # contact can be null when a jid listed in the metacontact data
@ -613,98 +769,7 @@ class Contacts:
def get_metacontacts_big_brother(self, family): 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)
return family[-1] return family[-1]
def is_pm_from_jid(self, account, jid):
'''Returns True if the given jid is a private message jid'''
if jid in self._contacts[account]:
return False
return True
def is_pm_from_contact(self, account, contact):
'''Returns True if the given contact is a private message contact'''
if isinstance(contact, Contact):
return False
return True
def get_jid_list(self, account):
return self._contacts[account].keys()
def contact_from_gc_contact(self, gc_contact):
'''Create a Contact instance from a GC_Contact instance'''
jid = gc_contact.get_full_jid()
return Contact(jid=jid, resource=gc_contact.resource,
name=gc_contact.name, groups=[], show=gc_contact.show,
status=gc_contact.status, sub='none', client_caps=gc_contact.client_caps)
def create_gc_contact(self, room_jid='', name='', show='', status='',
role='', affiliation='', jid='', resource=''):
return GC_Contact(room_jid, name, show, status, role, affiliation, jid,
resource)
def add_gc_contact(self, account, gc_contact):
# No such account before ?
if account not in self._gc_contacts:
self._contacts[account] = {gc_contact.room_jid : {gc_contact.name: \
gc_contact}}
return
# No such room_jid before ?
if gc_contact.room_jid not in self._gc_contacts[account]:
self._gc_contacts[account][gc_contact.room_jid] = {gc_contact.name: \
gc_contact}
return
self._gc_contacts[account][gc_contact.room_jid][gc_contact.name] = \
gc_contact
def remove_gc_contact(self, account, gc_contact):
if account not in self._gc_contacts:
return
if gc_contact.room_jid not in self._gc_contacts[account]:
return
if gc_contact.name not in self._gc_contacts[account][
gc_contact.room_jid]:
return
del self._gc_contacts[account][gc_contact.room_jid][gc_contact.name]
# It was the last nick in room ?
if not len(self._gc_contacts[account][gc_contact.room_jid]):
del self._gc_contacts[account][gc_contact.room_jid]
def remove_room(self, account, room_jid):
if account not in self._gc_contacts:
return
if room_jid not in self._gc_contacts[account]:
return
del self._gc_contacts[account][room_jid]
def get_gc_list(self, account):
if account not in self._gc_contacts:
return []
return self._gc_contacts[account].keys()
def get_nick_list(self, account, room_jid):
gc_list = self.get_gc_list(account)
if not room_jid in gc_list:
return []
return self._gc_contacts[account][room_jid].keys()
def get_gc_contact(self, account, room_jid, nick):
nick_list = self.get_nick_list(account, room_jid)
if not nick in nick_list:
return None
return self._gc_contacts[account][room_jid][nick]
def get_nb_role_total_gc_contacts(self, account, room_jid, role):
'''Returns the number of group chat contacts for the given role and the
total number of group chat contacts'''
if account not in self._gc_contacts:
return 0, 0
if room_jid not in self._gc_contacts[account]:
return 0, 0
nb_role = nb_total = 0
for nick in self._gc_contacts[account][room_jid]:
if self._gc_contacts[account][room_jid][nick].role == role:
nb_role += 1
nb_total += 1
return nb_role, nb_total
# vim: se ts=3: # vim: se ts=3:

View File

@ -27,7 +27,7 @@ docdir = '../'
datadir = '../' datadir = '../'
localedir = '../po' localedir = '../po'
version = '0.12.5.8-dev' version = '0.13.0.1-dev'
import sys, os.path import sys, os.path
for base in ('.', 'common'): for base in ('.', 'common'):

View File

@ -838,14 +838,27 @@ class Logger:
gzip.close() gzip.close()
data = string.getvalue() data = string.getvalue()
self.cur.execute(''' self.cur.execute('''
INSERT INTO caps_cache ( hash_method, hash, data ) INSERT INTO caps_cache ( hash_method, hash, data, last_seen )
VALUES (?, ?, ?); VALUES (?, ?, ?, ?);
''', (hash_method, hash_, buffer(data))) # (1) -- note above ''', (hash_method, hash_, buffer(data), int(time.time())))
# (1) -- note above
try: try:
self.con.commit() self.con.commit()
except sqlite.OperationalError, e: except sqlite.OperationalError, e:
print >> sys.stderr, str(e) print >> sys.stderr, str(e)
def update_caps_time(self, method, hash_):
sql = '''UPDATE caps_cache SET last_seen = %d
WHERE hash_method = "%s" and hash = "%s"''' % \
(int(time.time()), method, hash_)
self.simple_commit(sql)
def clean_caps_table(self):
'''Remove caps which was not seen for 3 months'''
sql = '''DELETE FROM caps_cache WHERE last_seen < %d''' % \
int(time.time() - 3*30*24*3600)
self.simple_commit(sql)
def replace_roster(self, account_name, roster_version, roster): def replace_roster(self, account_name, roster_version, roster):
''' Replace current roster in DB by a new one. ''' Replace current roster in DB by a new one.
accout_name is the name of the account to change accout_name is the name of the account to change

View File

@ -1,36 +0,0 @@
#!/usr/bin/python
import types
class VerboseClassType(type):
indent = ''
def __init__(cls, name, bases, dict):
super(VerboseClassType, cls).__init__(cls, name, bases, dict)
new = {}
print 'Initializing new class %s:' % cls
for fname, fun in dict.iteritems():
wrap = hasattr(fun, '__call__')
print '%s%s is %s, we %s wrap it.' % \
(cls.__class__.indent, fname, fun, wrap and 'will' or "won't")
if not wrap: continue
setattr(cls, fname, cls.wrap(name, fname, fun))
def wrap(cls, name, fname, fun):
def verbose(*a, **b):
args = ', '.join(map(repr, a)+map(lambda x:'%s=%r'%x, b.iteritems()))
print '%s%s.%s(%s):' % (cls.__class__.indent, name, fname, args)
cls.__class__.indent += '| '
r = fun(*a, **b)
cls.__class__.indent = cls.__class__.indent[:-4]
print '%s+=%r' % (cls.__class__.indent, r)
return r
verbose.__name__ = fname
return verbose
def nested_property(f):
ret = f()
p = {}
for v in ('fget', 'fset', 'fdel', 'doc'):
if v in ret: p[v]=ret[v]
return property(**p)

View File

@ -29,6 +29,7 @@
import os import os
import locale import locale
import re import re
from time import time
from common import gajim from common import gajim
from common import helpers from common import helpers
from common import caps from common import caps
@ -218,6 +219,8 @@ class OptionsParser:
self.update_config_to_01257() self.update_config_to_01257()
if old < [0, 12, 5, 8] and new >= [0, 12, 5, 8]: if old < [0, 12, 5, 8] and new >= [0, 12, 5, 8]:
self.update_config_to_01258() self.update_config_to_01258()
if old < [0, 13, 0, 1] and new >= [0, 13, 0, 1]:
self.update_config_to_01301()
gajim.logger.init_vars() gajim.logger.init_vars()
gajim.config.set('version', new_version) gajim.config.set('version', new_version)
@ -817,4 +820,23 @@ class OptionsParser:
'proxy.jabber.ru', 'proxy.jabbim.cz']) 'proxy.jabber.ru', 'proxy.jabbim.cz'])
gajim.config.set('version', '0.12.5.8') gajim.config.set('version', '0.12.5.8')
def update_config_to_01301(self):
back = os.getcwd()
os.chdir(logger.LOG_DB_FOLDER)
con = sqlite.connect(logger.LOG_DB_FILE)
os.chdir(back)
cur = con.cursor()
try:
cur.executescript(
'''
ALTER TABLE caps_cache
ADD last_seen INTEGER default %d;
''' % int(time())
)
con.commit()
except sqlite.OperationalError:
pass
con.close()
gajim.config.set('version', '0.13.0.1')
# vim: se ts=3: # vim: se ts=3:

View File

@ -1888,9 +1888,7 @@ class SubscriptionRequestWindow:
if self.jid in gajim.interface.instances[self.account]['infos']: if self.jid in gajim.interface.instances[self.account]['infos']:
gajim.interface.instances[self.account]['infos'][self.jid].window.present() gajim.interface.instances[self.account]['infos'][self.jid].window.present()
else: else:
contact = gajim.contacts.create_contact(jid=self.jid, name='', contact = gajim.contacts.create_contact(jid=self.jid, account=self.account)
groups=[], show='', status='', sub='', ask='', resource='',
priority=5, keyID='', our_chatstate=None, chatstate=None)
gajim.interface.instances[self.account]['infos'][self.jid] = \ gajim.interface.instances[self.account]['infos'][self.jid] = \
vcard.VcardWindow(contact, self.account) vcard.VcardWindow(contact, self.account)
# Remove jabber page # Remove jabber page

View File

@ -284,7 +284,7 @@ _('Connection with peer cannot be established.'))
if contact.find('/') == -1: if contact.find('/') == -1:
return return
(jid, resource) = contact.split('/', 1) (jid, resource) = contact.split('/', 1)
contact = gajim.contacts.create_contact(jid=jid, resource=resource) contact = gajim.contacts.create_contact(jid=jid, account=account, resource=resource)
file_name = os.path.split(file_path)[1] file_name = os.path.split(file_path)[1]
file_props = self.get_send_file_props(account, contact, file_props = self.get_send_file_props(account, contact,
file_path, file_name, file_desc) file_path, file_name, file_desc)

View File

@ -176,7 +176,7 @@ class PrivateChatControl(ChatControl):
ChatControl.update_ui(self) ChatControl.update_ui(self)
def update_contact(self): def update_contact(self):
self.contact = gajim.contacts.contact_from_gc_contact(self.gc_contact) self.contact = self.gc_contact.as_contact()
def begin_e2e_negotiation(self): def begin_e2e_negotiation(self):
self.no_autonegotiation = True self.no_autonegotiation = True
@ -1463,7 +1463,7 @@ class GroupchatControl(ChatControlBase):
self.draw_all_roles() self.draw_all_roles()
iter_ = model.append(role_iter, (None, nick, 'contact', name, None)) iter_ = model.append(role_iter, (None, nick, 'contact', name, None))
if not nick in gajim.contacts.get_nick_list(self.account, self.room_jid): if not nick in gajim.contacts.get_nick_list(self.account, self.room_jid):
gc_contact = gajim.contacts.create_gc_contact(room_jid=self.room_jid, gc_contact = gajim.contacts.create_gc_contact(room_jid=self.room_jid, account=self.account,
name=nick, show=show, status=status, role=role, name=nick, show=show, status=status, role=role,
affiliation=affiliation, jid=j, resource=resource) affiliation=affiliation, jid=j, resource=resource)
gajim.contacts.add_gc_contact(self.account, gc_contact) gajim.contacts.add_gc_contact(self.account, gc_contact)
@ -2254,14 +2254,14 @@ class GroupchatControl(ChatControlBase):
def on_info(self, widget, nick): def on_info(self, widget, nick):
'''Call vcard_information_window class to display user's information''' '''Call vcard_information_window class to display user's information'''
c = gajim.contacts.get_gc_contact(self.account, self.room_jid, nick) gc_contact = gajim.contacts.get_gc_contact(self.account, self.room_jid, nick)
c2 = gajim.contacts.contact_from_gc_contact(c) contact = gc_contact.as_contact()
if c2.jid in gajim.interface.instances[self.account]['infos']: if contact.jid in gajim.interface.instances[self.account]['infos']:
gajim.interface.instances[self.account]['infos'][c2.jid].window.\ gajim.interface.instances[self.account]['infos'][contact.jid].window.\
present() present()
else: else:
gajim.interface.instances[self.account]['infos'][c2.jid] = \ gajim.interface.instances[self.account]['infos'][contact.jid] = \
vcard.VcardWindow(c2, self.account, c) vcard.VcardWindow(contact, self.account, gc_contact)
def on_history(self, widget, nick): def on_history(self, widget, nick):
jid = gajim.construct_fjid(self.room_jid, nick) jid = gajim.construct_fjid(self.room_jid, nick)

View File

@ -352,11 +352,9 @@ class Interface:
# Ignore offline presence of unknown self resource # Ignore offline presence of unknown self resource
if new_show < 2: if new_show < 2:
return return
contact1 = gajim.contacts.create_contact(jid=ji, contact1 = gajim.contacts.create_self_contact(jid=ji,
name=gajim.nicks[account], groups=['self_contact'], account=account, show=array[1], status=status_message,
show=array[1], status=status_message, sub='both', ask='none', priority=priority, keyID=keyID, resource=resource)
priority=priority, keyID=keyID, resource=resource,
mood=conn.mood, tune=conn.tune, activity=conn.activity)
old_show = 0 old_show = 0
gajim.contacts.add_contact(account, contact1) gajim.contacts.add_contact(account, contact1)
lcontact.append(contact1) lcontact.append(contact1)
@ -541,8 +539,8 @@ class Interface:
show = model[iter_][3] show = model[iter_][3]
else: else:
show = 'offline' show = 'offline'
gc_c = gajim.contacts.create_gc_contact(room_jid = jid, gc_c = gajim.contacts.create_gc_contact(room_jid=jid, account=account,
name = nick, show = show) name=nick, show=show)
ctrl = self.new_private_chat(gc_c, account, session) ctrl = self.new_private_chat(gc_c, account, session)
ctrl.print_conversation(_('Error %(code)s: %(msg)s') % { ctrl.print_conversation(_('Error %(code)s: %(msg)s') % {
@ -620,8 +618,8 @@ class Interface:
keyID = attached_keys[attached_keys.index(jid) + 1] keyID = attached_keys[attached_keys.index(jid) + 1]
name = jid.split('@', 1)[0] name = jid.split('@', 1)[0]
name = name.split('%', 1)[0] name = name.split('%', 1)[0]
contact1 = gajim.contacts.create_contact(jid=jid, name=name, contact1 = gajim.contacts.create_contact(jid=jid, account=account,
groups=[], show='online', status='online', name=name, groups=[], show='online', status='online',
ask='to', resource=array[1], keyID=keyID) ask='to', resource=array[1], keyID=keyID)
gajim.contacts.add_contact(account, contact1) gajim.contacts.add_contact(account, contact1)
self.roster.add_contact(jid, account) self.roster.add_contact(jid, account)
@ -898,7 +896,7 @@ class Interface:
ctrl.print_conversation(_('%(nick)s is now known as %(new_nick)s') \ ctrl.print_conversation(_('%(nick)s is now known as %(new_nick)s') \
% {'nick': nick, 'new_nick': new_nick}, 'status') % {'nick': nick, 'new_nick': new_nick}, 'status')
gc_c = gajim.contacts.get_gc_contact(account, room_jid, new_nick) gc_c = gajim.contacts.get_gc_contact(account, room_jid, new_nick)
c = gajim.contacts.contact_from_gc_contact(gc_c) c = gc_c.as_contact()
ctrl.gc_contact = gc_c ctrl.gc_contact = gc_c
ctrl.contact = c ctrl.contact = c
if ctrl.session: if ctrl.session:
@ -1221,8 +1219,8 @@ class Interface:
if sub == 'remove': if sub == 'remove':
return return
# Add new contact to roster # Add new contact to roster
contact = gajim.contacts.create_contact(jid=jid, name=name, contact = gajim.contacts.create_contact(jid=jid, account=account,
groups=groups, show='offline', sub=sub, ask=ask) name=name, groups=groups, show='offline', sub=sub, ask=ask)
gajim.contacts.add_contact(account, contact) gajim.contacts.add_contact(account, contact)
self.roster.add_contact(jid, account) self.roster.add_contact(jid, account)
else: else:
@ -1361,9 +1359,8 @@ class Interface:
'attached_gpg_keys').split() 'attached_gpg_keys').split()
if jid in attached_keys: if jid in attached_keys:
keyID = attached_keys[attached_keys.index(jid) + 1] keyID = attached_keys[attached_keys.index(jid) + 1]
contact = gajim.contacts.create_contact(jid=jid, name='', contact = gajim.contacts.create_not_in_roster_contact(jid=jid,
groups=[_('Not in Roster')], show='not in roster', status='', account=account, keyID=keyID)
sub='none', keyID=keyID)
gajim.contacts.add_contact(account, contact) gajim.contacts.add_contact(account, contact)
self.roster.add_contact(contact.jid, account) self.roster.add_contact(contact.jid, account)
file_props = array[1] file_props = array[1]
@ -2233,7 +2230,7 @@ class Interface:
else: else:
show = 'offline' show = 'offline'
gc_contact = gajim.contacts.create_gc_contact( gc_contact = gajim.contacts.create_gc_contact(
room_jid = room_jid, name = nick, show = show) room_jid=room_jid, account=account, name=nick, show=show)
if not session: if not session:
session = gajim.connections[account].make_new_session( session = gajim.connections[account].make_new_session(
@ -2577,7 +2574,8 @@ class Interface:
account): account):
# Join new groupchat # Join new groupchat
if minimize: if minimize:
contact = gajim.contacts.create_contact(jid=room_jid, name=nick) #GCMIN
contact = gajim.contacts.create_contact(jid=room_jid, account=account, name=nick)
gc_control = GroupchatControl(None, contact, account) gc_control = GroupchatControl(None, contact, account)
gajim.interface.minimized_controls[account][room_jid] = gc_control gajim.interface.minimized_controls[account][room_jid] = gc_control
self.roster.add_groupchat(room_jid, account) self.roster.add_groupchat(room_jid, account)
@ -2600,7 +2598,8 @@ class Interface:
def new_room(self, room_jid, nick, account, is_continued=False): def new_room(self, room_jid, nick, account, is_continued=False):
# Get target window, create a control, and associate it with the window # Get target window, create a control, and associate it with the window
contact = gajim.contacts.create_contact(jid=room_jid, name=nick) # GCMIN
contact = gajim.contacts.create_contact(jid=room_jid, account=account, name=nick)
mw = self.msg_win_mgr.get_window(contact.jid, account) mw = self.msg_win_mgr.get_window(contact.jid, account)
if not mw: if not mw:
mw = self.msg_win_mgr.create_window(contact, account, mw = self.msg_win_mgr.create_window(contact, account,
@ -2610,7 +2609,7 @@ class Interface:
mw.new_tab(gc_control) mw.new_tab(gc_control)
def new_private_chat(self, gc_contact, account, session=None): def new_private_chat(self, gc_contact, account, session=None):
contact = gajim.contacts.contact_from_gc_contact(gc_contact) contact = gc_contact.as_contact()
type_ = message_control.TYPE_PM type_ = message_control.TYPE_PM
fjid = gc_contact.room_jid + '/' + gc_contact.name fjid = gc_contact.room_jid + '/' + gc_contact.name

View File

@ -688,9 +688,7 @@ class RosterWindow:
is_observer = contact.is_observer() is_observer = contact.is_observer()
if is_observer: if is_observer:
# if he has a tag, remove it # if he has a tag, remove it
tag = gajim.contacts.get_metacontacts_tag(account, jid) gajim.contacts.remove_metacontact(account, jid)
if tag:
gajim.contacts.remove_metacontact(account, jid)
# Add contact to roster # Add contact to roster
family = gajim.contacts.get_metacontacts_family(account, jid) family = gajim.contacts.get_metacontacts_family(account, jid)
@ -822,7 +820,8 @@ class RosterWindow:
else: else:
name = jid.split('@')[0] name = jid.split('@')[0]
# New groupchat # New groupchat
contact = gajim.contacts.create_contact(jid=jid, name=name, #GCMIN
contact = gajim.contacts.create_contact(jid=jid, account=account, name=name,
groups=[_('Groupchats')], show=show, status=status, sub='none') groups=[_('Groupchats')], show=show, status=status, sub='none')
gajim.contacts.add_contact(account, contact) gajim.contacts.add_contact(account, contact)
self.add_contact(jid, account) self.add_contact(jid, account)
@ -857,7 +856,8 @@ class RosterWindow:
Return the added contact instance.''' Return the added contact instance.'''
contact = gajim.contacts.get_contact_with_highest_priority(account, jid) contact = gajim.contacts.get_contact_with_highest_priority(account, jid)
if contact is None: if contact is None:
contact = gajim.contacts.create_contact(jid=jid, name=jid, #TRANSP
contact = gajim.contacts.create_contact(jid=jid, account=account, name=jid,
groups=[_('Transports')], show='offline', status='offline', groups=[_('Transports')], show='offline', status='offline',
sub='from') sub='from')
gajim.contacts.add_contact(account, contact) gajim.contacts.add_contact(account, contact)
@ -998,9 +998,8 @@ class RosterWindow:
'attached_gpg_keys').split() 'attached_gpg_keys').split()
if jid in attached_keys: if jid in attached_keys:
keyID = attached_keys[attached_keys.index(jid) + 1] keyID = attached_keys[attached_keys.index(jid) + 1]
contact = gajim.contacts.create_contact(jid=jid, name=nick, contact = gajim.contacts.create_not_in_roster_contact(jid=jid,
groups=[_('Not in Roster')], show='not in roster', status='', account=account, resource=resource, name=nick, keyID=keyID)
sub='none', resource=resource, keyID=keyID)
gajim.contacts.add_contact(account, contact) gajim.contacts.add_contact(account, contact)
self.add_contact(contact.jid, account) self.add_contact(contact.jid, account)
return contact return contact
@ -1788,7 +1787,8 @@ class RosterWindow:
if gajim.jid_is_transport(jid): if gajim.jid_is_transport(jid):
array[jid]['groups'] = [_('Transports')] array[jid]['groups'] = [_('Transports')]
contact1 = gajim.contacts.create_contact(jid=ji, name=name, #TRANSP - potential
contact1 = gajim.contacts.create_contact(jid=ji, account=account, name=name,
groups=array[jid]['groups'], show=show, status=status, groups=array[jid]['groups'], show=show, status=status,
sub=array[jid]['subscription'], ask=array[jid]['ask'], sub=array[jid]['subscription'], ask=array[jid]['ask'],
resource=resource, keyID=keyID) resource=resource, keyID=keyID)
@ -1935,7 +1935,7 @@ class RosterWindow:
'attached_gpg_keys').split() 'attached_gpg_keys').split()
if jid in attached_keys: if jid in attached_keys:
keyID = attached_keys[attached_keys.index(jid) + 1] keyID = attached_keys[attached_keys.index(jid) + 1]
contact = gajim.contacts.create_contact(jid=jid, name=nickname, contact = gajim.contacts.create_contact(jid=jid, account=account, name=nickname,
groups=groups, show='requested', status='', ask='none', groups=groups, show='requested', status='', ask='none',
sub='subscribe', keyID=keyID) sub='subscribe', keyID=keyID)
gajim.contacts.add_contact(account, contact) gajim.contacts.add_contact(account, contact)
@ -2525,7 +2525,7 @@ class RosterWindow:
account_name = account account_name = account
if gajim.account_is_connected(account): if gajim.account_is_connected(account):
account_name += ' (%s/%s)' % (repr(nbr_on), repr(nbr_total)) account_name += ' (%s/%s)' % (repr(nbr_on), repr(nbr_total))
contact = gajim.contacts.create_contact(jid=jid, name=account_name, contact = gajim.contacts.create_contact(jid=jid, account=account, name=account_name,
show=connection.get_status(), sub='', status=connection.status, show=connection.get_status(), sub='', status=connection.status,
resource=connection.server_resource, resource=connection.server_resource,
priority=connection.priority, mood=connection.mood, priority=connection.priority, mood=connection.mood,
@ -2554,11 +2554,10 @@ class RosterWindow:
show = roster.getShow(jid+'/'+resource) show = roster.getShow(jid+'/'+resource)
if not show: if not show:
show = 'online' show = 'online'
contact = gajim.contacts.create_contact(jid=jid, contact = gajim.contacts.create_self_contact(jid=jid,
name=account, groups=['self_contact'], show=show, account=account, show=show, status=roster.getStatus(jid + '/' + resource),
status=roster.getStatus(jid + '/' + resource), priority=roster.getPriority(jid + '/' + resource),
resource=resource, resource=resource)
priority=roster.getPriority(jid + '/' + resource))
contacts.append(contact) contacts.append(contact)
if self.tooltip.timeout == 0 or self.tooltip.id != props[0]: if self.tooltip.timeout == 0 or self.tooltip.id != props[0]:
self.tooltip.id = row self.tooltip.id = row
@ -5116,7 +5115,7 @@ class RosterWindow:
service_discovery_menuitem.connect('activate', service_discovery_menuitem.connect('activate',
self.on_service_disco_menuitem_activate, account) self.on_service_disco_menuitem_activate, account)
hostname = gajim.config.get_per('accounts', account, 'hostname') hostname = gajim.config.get_per('accounts', account, 'hostname')
contact = gajim.contacts.create_contact(jid=hostname) # Fake contact contact = gajim.contacts.create_contact(jid=hostname, account=account) # Fake contact
execute_command_menuitem.connect('activate', execute_command_menuitem.connect('activate',
self.on_execute_command, contact, account) self.on_execute_command, contact, account)

View File

@ -110,9 +110,7 @@ class SearchWindow:
if jid in gajim.interface.instances[self.account]['infos']: if jid in gajim.interface.instances[self.account]['infos']:
gajim.interface.instances[self.account]['infos'][jid].window.present() gajim.interface.instances[self.account]['infos'][jid].window.present()
else: else:
contact = gajim.contacts.create_contact(jid = jid, name='', groups=[], contact = gajim.contacts.create_contact(jid=jid, account=self.account)
show='', status='', sub='', ask='', resource='', priority=0,
keyID='', our_chatstate=None, chatstate=None)
gajim.interface.instances[self.account]['infos'][jid] = \ gajim.interface.instances[self.account]['infos'][jid] = \
vcard.VcardWindow(contact, self.account) vcard.VcardWindow(contact, self.account)

View File

@ -203,7 +203,8 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
if not contact: if not contact:
# contact is not in the roster, create a fake one to display # contact is not in the roster, create a fake one to display
# notification # notification
contact = contacts.Contact(jid=jid, resource=resource) contact = gajim.contacts.create_not_in_roster_contact(jid=jid,
account=self.conn.name, resource=resource)
advanced_notif_num = notify.get_advanced_notification('message_received', advanced_notif_num = notify.get_advanced_notification('message_received',
self.conn.name, contact) self.conn.name, contact)
@ -506,7 +507,7 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
contact = gajim.contacts.get_contact(account, self.jid, resource) contact = gajim.contacts.get_contact(account, self.jid, resource)
if not contact: if not contact:
contact = gajim.contacts.create_contact(jid=jid, contact = gajim.contacts.create_contact(jid=jid, account=account,
resource=resource, show=self.conn.get_status()) resource=resource, show=self.conn.get_status())
gajim.interface.new_chat(contact, account, resource=resource, gajim.interface.new_chat(contact, account, resource=resource,

View File

@ -7,6 +7,7 @@ import lib
lib.setup_env() lib.setup_env()
from common import gajim from common import gajim
from common import contacts as contacts_module
from gajim import Interface from gajim import Interface
from gajim_mocks import * from gajim_mocks import *
@ -25,6 +26,9 @@ class TestStatusChange(unittest.TestCase):
'''tests gajim.py's incredibly complex handle_event_notify''' '''tests gajim.py's incredibly complex handle_event_notify'''
def setUp(self): def setUp(self):
gajim.connections = {}
gajim.contacts = contacts_module.Contacts()
gajim.interface.roster = roster_window.RosterWindow() gajim.interface.roster = roster_window.RosterWindow()
for acc in contacts: for acc in contacts:
@ -38,13 +42,6 @@ class TestStatusChange(unittest.TestCase):
self.assertEqual(0, len(notify.notifications)) self.assertEqual(0, len(notify.notifications))
def tearDown(self): def tearDown(self):
gajim.interface.roster.model.clear()
for acc in contacts:
gajim.contacts.clear_contacts(acc)
del gajim.interface.roster
notify.notifications = [] notify.notifications = []
def contact_comes_online(self, account, jid, resource, prio): def contact_comes_online(self, account, jid, resource, prio):

View File

@ -9,15 +9,16 @@ from mock import Mock, expectParams
from gajim_mocks import * from gajim_mocks import *
from common import gajim from common import gajim
from common import contacts as contacts_module
import roster_window import roster_window
gajim.get_jid_from_account = lambda acc: 'myjid@' + acc gajim.get_jid_from_account = lambda acc: 'myjid@' + acc
class TestRosterWindow(unittest.TestCase): class TestRosterWindow(unittest.TestCase):
def setUp(self): def setUp(self):
gajim.interface = MockInterface() gajim.interface = MockInterface()
self.roster = roster_window.RosterWindow()
self.C_NAME = roster_window.C_NAME self.C_NAME = roster_window.C_NAME
self.C_TYPE = roster_window.C_TYPE self.C_TYPE = roster_window.C_TYPE
@ -26,13 +27,13 @@ class TestRosterWindow(unittest.TestCase):
# Add after creating RosterWindow # Add after creating RosterWindow
# We want to test the filling explicitly # We want to test the filling explicitly
gajim.contacts = contacts_module.Contacts()
gajim.connections = {}
self.roster = roster_window.RosterWindow()
for acc in contacts: for acc in contacts:
gajim.connections[acc] = MockConnection(acc) gajim.connections[acc] = MockConnection(acc)
gajim.contacts.add_account(acc)
def tearDown(self):
self.roster.model.clear()
for acc in gajim.contacts.get_accounts():
gajim.contacts.clear_contacts(acc)
### Custom assertions ### Custom assertions
def assert_all_contacts_are_in_roster(self, acc): def assert_all_contacts_are_in_roster(self, acc):
@ -142,11 +143,6 @@ class TestRosterWindow(unittest.TestCase):
groups = contacts[acc][jid]['groups'] or ['General',] groups = contacts[acc][jid]['groups'] or ['General',]
# cleanup
self.roster.model.clear()
for acc in contacts:
gajim.contacts.clear_contacts(acc)
def test_fill_roster_model(self): def test_fill_roster_model(self):
for acc in contacts: for acc in contacts:
self.roster.fill_contacts_and_groups_dicts(contacts[acc], acc) self.roster.fill_contacts_and_groups_dicts(contacts[acc], acc)
@ -190,7 +186,7 @@ class TestRosterWindowMetaContacts(TestRosterWindowRegrouped):
self.test_fill_roster_model() self.test_fill_roster_model()
jid = u'coolstuff@gajim.org' jid = u'coolstuff@gajim.org'
contact = gajim.contacts.create_contact(jid) contact = gajim.contacts.create_contact(jid, account1)
gajim.contacts.add_contact(account1, contact) gajim.contacts.add_contact(account1, contact)
self.roster.add_contact(jid, account1) self.roster.add_contact(jid, account1)
self.roster.chg_contact_status(contact, 'offline', '', account1) self.roster.chg_contact_status(contact, 'offline', '', account1)

View File

@ -41,6 +41,7 @@ modules = ( 'unit.test_xmpp_dispatcher_nb',
'unit.test_contacts', 'unit.test_contacts',
'unit.test_gui_interface', 'unit.test_gui_interface',
'unit.test_sessions', 'unit.test_sessions',
'unit.test_account',
) )
#modules = () #modules = ()

21
test/unit/test_account.py Normal file
View File

@ -0,0 +1,21 @@
'''
Tests for Account classes
'''
import unittest
import lib
lib.setup_env()
from common.account import Account
class Test(unittest.TestCase):
def testInstantiate(self):
account = Account(name='MyAcc', contacts=None, gc_contacts=None)
self.assertEquals('MyAcc', account.name)
self.assertTrue(account.gc_contacts is None)
self.assertTrue(account.contacts is None)
if __name__ == "__main__":
unittest.main()

View File

@ -66,9 +66,9 @@ class TestCapsCache(CommonCapsTest):
def test_initialize_from_db(self): def test_initialize_from_db(self):
''' Read cashed dummy data from db ''' ''' Read cashed dummy data from db '''
self.assertEqual(self.cc[self.client_caps].queried, 0) self.assertEqual(self.cc[self.client_caps].status, caps.NEW)
self.cc.initialize_from_db() self.cc.initialize_from_db()
self.assertEqual(self.cc[self.client_caps].queried, 2) self.assertEqual(self.cc[self.client_caps].status, caps.CACHED)
def test_preload_triggering_query(self): def test_preload_triggering_query(self):
''' Make sure that preload issues a disco ''' ''' Make sure that preload issues a disco '''
@ -113,25 +113,23 @@ class TestClientCaps(CommonCapsTest):
"http://gajim.org#m3P2WeXPMGVH2tZPe7yITnfY0Dw=") "http://gajim.org#m3P2WeXPMGVH2tZPe7yITnfY0Dw=")
def test_client_supports(self): def test_client_supports(self):
contact = Contact(client_caps=self.client_caps) self.assertTrue(caps.client_supports(self.client_caps, NS_PING),
self.assertTrue(contact.supports(NS_PING),
msg="Assume supported, if we don't have caps") msg="Assume supported, if we don't have caps")
self.assertFalse(contact.supports(NS_XHTML_IM), self.assertFalse(caps.client_supports(self.client_caps, NS_XHTML_IM),
msg="Must not assume blacklisted feature is supported on default") msg="Must not assume blacklisted feature is supported on default")
self.cc.initialize_from_db() self.cc.initialize_from_db()
self.assertFalse(contact.supports(NS_PING), self.assertFalse(caps.client_supports(self.client_caps, NS_PING),
msg="Must return false on unsupported feature") msg="Must return false on unsupported feature")
self.assertTrue(contact.supports(NS_XHTML_IM), self.assertTrue(caps.client_supports(self.client_caps, NS_XHTML_IM),
msg="Must return True on supported feature") msg="Must return True on supported feature")
self.assertTrue(contact.supports(NS_MUC), self.assertTrue(caps.client_supports(self.client_caps, NS_MUC),
msg="Must return True on supported feature") msg="Must return True on supported feature")
class TestOldClientCaps(TestClientCaps): class TestOldClientCaps(TestClientCaps):

View File

@ -6,7 +6,7 @@ import unittest
import lib import lib
lib.setup_env() lib.setup_env()
from common.contacts import CommonContact, Contact, GC_Contact from common.contacts import CommonContact, Contact, GC_Contact, Contacts
from common.xmpp import NS_MUC from common.xmpp import NS_MUC
from common import caps from common import caps
@ -14,9 +14,9 @@ from common import caps
class TestCommonContact(unittest.TestCase): class TestCommonContact(unittest.TestCase):
def setUp(self): def setUp(self):
self.contact = CommonContact(jid='', resource='', show='', status='', self.contact = CommonContact(jid='', account="", resource='', show='',
name='', our_chatstate=None, composing_xep=None, chatstate=None, status='', name='', our_chatstate=None, composing_xep=None,
client_caps=None) chatstate=None, client_caps=None)
def test_default_client_supports(self): def test_default_client_supports(self):
''' '''
@ -31,21 +31,99 @@ class TestCommonContact(unittest.TestCase):
self.assertTrue(self.contact.supports(NS_MUC), self.assertTrue(self.contact.supports(NS_MUC),
msg="Must not backtrace on simple check for supported feature") msg="Must not backtrace on simple check for supported feature")
class TestContact(TestCommonContact): class TestContact(TestCommonContact):
def setUp(self): def setUp(self):
TestCommonContact.setUp(self) TestCommonContact.setUp(self)
self.contact = Contact() self.contact = Contact(jid="test@gajim.org", account="account")
def test_attributes_available(self):
'''This test supports the migration from the old to the new contact
domain model by smoke testing that no attribute values are lost'''
attributes = ["jid", "resource", "show", "status", "name", "our_chatstate",
"composing_xep", "chatstate", "client_caps", "priority", "sub"]
for attr in attributes:
self.assertTrue(hasattr(self.contact, attr), msg="expected: " + attr)
class TestGC_Contact(TestCommonContact): class TestGC_Contact(TestCommonContact):
def setUp(self): def setUp(self):
TestCommonContact.setUp(self) TestCommonContact.setUp(self)
self.contact = GC_Contact() self.contact = GC_Contact(room_jid="confernce@gajim.org", account="account")
def test_attributes_available(self):
'''This test supports the migration from the old to the new contact
domain model by asserting no attributes have been lost'''
attributes = ["jid", "resource", "show", "status", "name", "our_chatstate",
"composing_xep", "chatstate", "client_caps", "role", "room_jid"]
for attr in attributes:
self.assertTrue(hasattr(self.contact, attr), msg="expected: " + attr)
class TestContacts(unittest.TestCase):
def setUp(self):
self.contacts = Contacts()
def test_create_add_get_contact(self):
jid = 'test@gajim.org'
account = "account"
contact = self.contacts.create_contact(jid=jid, account=account)
self.contacts.add_contact(account, contact)
retrieved_contact = self.contacts.get_contact(account, jid)
self.assertEqual(contact, retrieved_contact, "Contact must be known")
self.contacts.remove_contact(account, contact)
retrieved_contact = self.contacts.get_contact(account, jid)
self.assertNotEqual(contact, retrieved_contact,
msg="Contact must not be known any longer")
def test_copy_contact(self):
jid = 'test@gajim.org'
account = "account"
contact = self.contacts.create_contact(jid=jid, account=account)
copy = self.contacts.copy_contact(contact)
self.assertFalse(contact is copy, msg="Must not be the same")
# Not yet implemented to remain backwart compatible
# self.assertEqual(contact, copy, msg="Must be equal")
def test_legacy_accounts_handling(self):
self.contacts.add_account("one")
self.contacts.add_account("two")
self.contacts.change_account_name("two", "old")
self.contacts.remove_account("one")
self.assertEqual(["old"], self.contacts.get_accounts())
def test_legacy_contacts_from_groups(self):
jid1 = "test1@gajim.org"
jid2 = "test2@gajim.org"
account = "account"
group = "GroupA"
contact1 = self.contacts.create_contact(jid=jid1, account=account,
groups=[group])
self.contacts.add_contact(account, contact1)
contact2 = self.contacts.create_contact(jid=jid2, account=account,
groups=[group])
self.contacts.add_contact(account, contact2)
self.assertEqual(2, len(self.contacts.get_contacts_from_group(account, group)))
self.assertEqual(0, len(self.contacts.get_contacts_from_group(account, '')))
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()