import traceback
from util import callsback
import common.actions
action = common.actions.action
ObservableActionMeta = common.actions.ObservableActionMeta
from common import profile
from logging import getLogger; log = getLogger('Contact')
objget = object.__getattribute__
CONTACT_ATTRS = set(['id', 'buddy', 'remove', 'watched', '__repr__',
                     'rename_gui', 'rename', 'edit_alerts', 'alias', 'get_group', 'move_to_group'
                     '__getattr__', '__hash__', '__cmp__', 'sort', '_notify_dirty',
class Contact(object):
    Contact. Represents an entry on a protocol buddy list.
    Several contacts may point to the same Buddy object.
    Ex: AIM when a buddy is in 2+ groups - same buddy in both
    places but each has its own SSI.
    watched = 'online '.split()
    __metaclass__ = ObservableActionMeta
    def __init__(self, buddy, id):
        self.buddy, = buddy, id
        self._metacontact = None
    def remove(self):
    def _compatible_accounts(self):
        from common.protocolmeta import is_compatible
        result = []
        for account in profile.connected_accounts:
            if is_compatible(account.protocol, self.buddy.service):
        return result
    def _all_buddies(self, check_if_has=False):
        result = []
        for account in self._compatible_accounts():
            connection = account.connection
            if connection:
                if not check_if_has or connection.has_buddy(
                    # don't let a protocol create the buddy
                    buddy = connection.get_buddy(
                    if buddy is not None:
        return result
    def _is_blocked(self):
        buddies = [buddy.blocked for buddy in self._all_buddies(check_if_has=True)]
        return bool(buddies and all(buddies))
    blocked = property(_is_blocked)
    def _block_pred(self, block=True, **k):
        return True if bool(block) ^ self._is_blocked() else None
    def _unblock_pred(self, *a, **k):
        return True if self._is_blocked() else None
    def block(self, block=True, **k):
        for buddy in self._all_buddies():
            if bool(block) ^ bool(buddy.blocked):
                buddy.block(block, **k)
    def unblock(self, *a,**k):
    def get_notify_dirty(self):
        return self.buddy._notify_dirty
    def set_notify_dirty(self, value):
        self.buddy._notify_dirty = value
    _notify_dirty = property(get_notify_dirty, set_notify_dirty)
    def rename_gui(self):
        from gui.toolbox import GetTextFromUser
        localalias = self.alias
        if localalias is None:
            localalias = ''
        s = GetTextFromUser(_('Enter an alias for %s:') %,
                                           caption = _('Rename %s') %,
                                           default_value = localalias )
        if s is not None:
            if s == '' or s.strip():
                # dialog returns None if "Cancel" button is pressed -- that means do nothing
                # rename expects None to mean "no alias" and anything else to mean an alias--so
                # do the bool check to turn '' into None here.
                self.rename(s if s else None)
                return s
    def rename(self, new_alias):'setting alias for %r to %r', self, new_alias)
        profile.set_contact_info(self, 'alias', new_alias)
    def edit_alerts(self):
        import gui.pref.prefsdialog as prefsdialog'notifications')
    def alias(self):
        a = profile.get_contact_info(self, 'alias')
        if a: return a
        for attr in ('local_alias', 'remote_alias', 'nice_name'):
                a = getattr(self, attr, None)
            except Exception:
            if a: return a
    def get_group(self):
        g = self.protocol.group_for(self)
        assert isinstance(g, (basestring, type(None))), 'Is %s' % type(g)
        return g
    def move_to_group(self, groupname, index = 0, callback = None):
        if not isinstance(groupname, basestring):
            raise TypeError, 'groupname must be a string: %r' % groupname
        self.protocol.move_buddy_creating_group(self, groupname, self.get_group(),
                                                index, callback = callback)
    def __getattr__(self, attr):
        if attr in CONTACT_ATTRS:
            return objget(self, attr)
            return getattr(objget(self, 'buddy'), attr)
    def __repr__(self):
        return '<%s %s>' % (self.__class__.__name__, self.buddy)
    def __hash__(self):
        # First part of this hash should match Buddy.idstr()
        b = self.buddy
        id =
        if isinstance(id, bytes):
            id = id.decode('fuzzy utf-8')
        return hash(u'/'.join((, b.protocol.username,, unicode(id))))
    def __cmp__(self, other):
        if self is other:
            return 0
            return cmp((self.buddy,, (getattr(other, 'buddy', None), getattr(other, 'id', None)))
class ContactCapabilities:
    'Buddy capabilities. Exposed as common.caps'
    INFO          = 'INFO'
    IM            = 'IM'
    'Instant messaging.'
    FILES         = 'FILES'
    'Sending and receiving files.'
    'Sharing pictures over a direct connection.'
    SMS           = 'SMS'
    'Sending messages directly to a cell phone.'
    'Blocking buddies.'
    EMAIL         = 'EMAIL'
    'Sending email.'
    BOT = 'BOT'
    'User is a bot, and will join the Machines when Skynet turns on the human race. Be vigilant.'
    'Video chat.'