diff options
Diffstat (limited to 'sunshine/channel')
-rw-r--r-- | sunshine/channel/Makefile.am | 5 | ||||
-rw-r--r-- | sunshine/channel/__init__.py | 18 | ||||
-rw-r--r-- | sunshine/channel/contact_list.py | 371 | ||||
-rw-r--r-- | sunshine/channel/group.py | 223 | ||||
-rw-r--r-- | sunshine/channel/text.py | 198 |
5 files changed, 815 insertions, 0 deletions
diff --git a/sunshine/channel/Makefile.am b/sunshine/channel/Makefile.am new file mode 100644 index 0000000..875550b --- /dev/null +++ b/sunshine/channel/Makefile.am @@ -0,0 +1,5 @@ +channeldir = $(pythondir)/sunshine/channel +channel_PYTHON = contact_list.py \ + group.py \ + __init__.py \ + text.py diff --git a/sunshine/channel/__init__.py b/sunshine/channel/__init__.py new file mode 100644 index 0000000..7a6b8a1 --- /dev/null +++ b/sunshine/channel/__init__.py @@ -0,0 +1,18 @@ +# telepathy-sunshine is the GaduGadu connection manager for Telepathy +# +# Copyright (C) 2006-2007 Ali Sabil <ali.sabil@gmail.com> +# Copyright (C) 2010 Krzysztof Klinikowski <kkszysiu@gmail.com> +# +# This program 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; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA diff --git a/sunshine/channel/contact_list.py b/sunshine/channel/contact_list.py new file mode 100644 index 0000000..31b4a02 --- /dev/null +++ b/sunshine/channel/contact_list.py @@ -0,0 +1,371 @@ +# telepathy-sunshine is the GaduGadu connection manager for Telepathy +# +# Copyright (C) 2006-2007 Ali Sabil <ali.sabil@gmail.com> +# Copyright (C) 2010 Krzysztof Klinikowski <kkszysiu@gmail.com> +# +# This program 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; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import logging +import weakref + +import telepathy + +import xml.etree.ElementTree as ET + +from sunshine.util.decorator import async +from sunshine.handle import SunshineHandleFactory + +from sunshine.lqsoft.pygadu.twisted_protocol import GaduClient +from sunshine.lqsoft.pygadu.models import GaduProfile, GaduContact + +__all__ = ['SunshineContactListChannelFactory'] + +logger = logging.getLogger('Sunshine.ContactListChannel') + +class HandleMutex(object): + def __init__(self): + self._handles = set() + self._keys = {} + self._callbacks = {} + + def is_locked(self, handle): + return (handle in self._handles) + + def is_owned(self, key, handle): + return (handle in self._handles and self._keys[handle] == key) + + def lock(self, key, handle): + if self.is_locked(handle): + return False + self._handles.add(handle) + self._keys[handle] = key + return True + + def unlock(self, key, handle): + if not self.is_owned(key, handle): + return + self._handles.remove(handle) + del self._keys[handle] + callbacks = self._callbacks.get(handle, [])[:] + self._callbacks[handle] = [] + for callback in callbacks: + callback[0](*callback[1:]) + + def add_callback(self, key, handle, callback): + if self.is_owned(key, handle): + return + if not self.is_locked(handle): + callback[0](*callback[1:]) + else: + self._callbacks.setdefault(handle, []).append(callback) + +class Lockable(object): + def __init__(self, mutex, key, cb_name): + self._mutex = mutex + self._key = key + self._cb_name = cb_name + + def __call__(self, func): + def method(object, handle, *args, **kwargs): + def finished_cb(*user_data): + self._mutex.unlock(self._key, handle) + + def unlocked_cb(): + self._mutex.lock(self._key, handle) + kwargs[self._cb_name] = finished_cb + if func(object, handle, *args, **kwargs): + finished_cb() + + self._mutex.add_callback(self._key, handle, (unlocked_cb,)) + + return method + +mutex = HandleMutex() + + +def SunshineContactListChannelFactory(connection, manager, handle, props): + handle = connection.handle( + props[telepathy.CHANNEL_INTERFACE + '.TargetHandleType'], + props[telepathy.CHANNEL_INTERFACE + '.TargetHandle']) + + if handle.get_name() == 'subscribe': + channel_class = SunshineSubscribeListChannel + #hacky & tricky +# elif handle.get_name() == 'publish': +# channel_class = SunshineSubscribeListChannel + +# elif handle.get_name() == 'publish': +# channel_class = ButterflyPublishListChannel +# elif handle.get_name() == 'hide': +# channel_class = ButterflyHideListChannel +# elif handle.get_name() == 'allow': +# channel_class = ButterflyAllowListChannel +# elif handle.get_name() == 'deny': +# channel_class = ButterflyDenyListChannel + else: + raise TypeError("Unknown list type : " + handle.get_name()) + return channel_class(connection, manager, props) + + +class SunshineListChannel( + telepathy.server.ChannelTypeContactList, + telepathy.server.ChannelInterfaceGroup): + "Abstract Contact List channels" + + def __init__(self, connection, manager, props): + self._conn_ref = weakref.ref(connection) + telepathy.server.ChannelTypeContactList.__init__(self, connection, manager, props) + telepathy.server.ChannelInterfaceGroup.__init__(self) + self._populate(connection) + + def GetLocalPendingMembersWithInfo(self): + return [] + + # papyon.event.AddressBookEventInterface + def on_addressbook_contact_added(self, contact): + added = set() + local_pending = set() + remote_pending = set() + + ad, lp, rp = self._filter_contact(contact) + if ad or lp or rp: + handle = ButterflyHandleFactory(self._conn_ref(), 'contact', + contact.account, contact.network_id) + if ad: added.add(handle) + if lp: local_pending.add(handle) + if rp: remote_pending.add(handle) + msg = contact.attributes.get('invite_message', '') + self.MembersChanged(msg, added, (), local_pending, remote_pending, 0, + telepathy.CHANNEL_GROUP_CHANGE_REASON_NONE) + + # papyon.event.AddressBookEventInterface + def on_addressbook_contact_deleted(self, contact): + handle = ButterflyHandleFactory(self._conn_ref(), 'contact', + contact.account, contact.network_id) + ad, lp, rp = self._filter_contact(contact) + if self._contains_handle(handle) and not ad: + self.MembersChanged('', (), [handle], (), (), 0, + telepathy.CHANNEL_GROUP_CHANGE_REASON_NONE) + + # papyon.event.AddressBookEventInterface + def on_addressbook_contact_blocked(self, contact): + pass + + # papyon.event.AddressBookEventInterface + def on_addressbook_contact_unblocked(self, contact): + pass + + @async + def _populate(self, connection): + added = set() + local_pending = set() + remote_pending = set() + + for contact in connection.gadu_client.contacts: + #logger.info("New contact %s, name: %s added." % (contact.uin, contact.ShowName)) + ad, lp, rp = self._filter_contact(contact) + if ad or lp or rp: + handle = SunshineHandleFactory(self._conn_ref(), 'contact', + contact.uin, None) + if ad: added.add(handle) + if lp: local_pending.add(handle) + if rp: remote_pending.add(handle) + self.MembersChanged('', added, (), local_pending, remote_pending, 0, + telepathy.CHANNEL_GROUP_CHANGE_REASON_NONE) + + def _filter_contact(self, contact): + return (False, False, False) + + def _contains_handle(self, handle): + members, local_pending, remote_pending = self.GetAllMembers() + return (handle in members) or (handle in local_pending) or \ + (handle in remote_pending) + + +class SunshineSubscribeListChannel(SunshineListChannel): + """Subscribe List channel. + + This channel contains the list of contact to whom the current used is + 'subscribed', basically this list contains the contact for whom you are + supposed to receive presence notification.""" + + def __init__(self, connection, manager, props): + SunshineListChannel.__init__(self, connection, manager, props) + self.GroupFlagsChanged(telepathy.CHANNEL_GROUP_FLAG_CAN_ADD | + telepathy.CHANNEL_GROUP_FLAG_CAN_REMOVE, 0) + + def AddMembers(self, contacts, message): + logger.info("Subscribe - AddMembers called") + for h in contacts: + handle = self._conn.handle(telepathy.constants.HANDLE_TYPE_CONTACT, h) + contact_xml = ET.Element("Contact") + ET.SubElement(contact_xml, "Guid").text = str(handle.name) + ET.SubElement(contact_xml, "GGNumber").text = str(handle.name) + ET.SubElement(contact_xml, "ShowName").text = str(handle.name) + ET.SubElement(contact_xml, "Groups") + c = GaduContact.from_xml(contact_xml) + self._conn_ref().gadu_client.addContact( c ) + #config.addNewContact( c ) + self._conn_ref().gadu_client.notifyAboutContact( c ) + logger.info("Adding contact: %s" % (handle.name)) + self.MembersChanged('', [handle], (), (), (), 0, + telepathy.CHANNEL_GROUP_CHANGE_REASON_INVITED) + + #alias and group settings for new contacts are bit tricky + #try to set alias + handle.contact.ShowName = self._conn_ref().get_contact_alias(handle.id) + #and group + if self._conn_ref().pending_contacts_to_group.has_key(handle.name): + logger.info("Trying to add temporary group.") + print str(self._conn_ref().pending_contacts_to_group) + print str(self._conn_ref().pending_contacts_to_group[handle.name]) + handle.contact.updateGroups(self._conn_ref().pending_contacts_to_group[handle.name]) + logger.info("Contact added.") + + def RemoveMembers(self, contacts, message): + for h in contacts: + self._remove(h) + + def _filter_contact(self, contact): + return (True, False, False) + #return (contact.is_member(papyon.Membership.FORWARD) and not + # contact.is_member(papyon.Membership.PENDING), False, False) + + #@Lockable(mutex, 'add_subscribe', 'finished_cb') +# def _add(self, handle_id, message, finished_cb): +# logger.info("Subscribe - Add Members called.") +# handle = self._conn.handle(telepathy.HANDLE_TYPE_CONTACT, handle_id) +# if handle.contact is not None and \ +# handle.contact.is_member(papyon.Membership.FORWARD): +# return True +# +# account = handle.account +# network = handle.network +# groups = list(handle.pending_groups) +# handle.pending_groups = set() +# ab = self._conn.msn_client.address_book +# ab.add_messenger_contact(account, +# network_id=network, +# auto_allow=False, +# invite_message=message.encode('utf-8'), +# groups=groups, +# done_cb=(finished_cb,), +# failed_cb=(finished_cb,)) + + @Lockable(mutex, 'rem_subscribe', 'finished_cb') + def _remove(self, handle_id, finished_cb): + handle = self._conn.handle(telepathy.HANDLE_TYPE_CONTACT, handle_id) + contact = handle.contact + if contact is None or not contact.is_member(papyon.Membership.FORWARD): + return True + ab = self._conn.msn_client.address_book + ab.delete_contact(contact, done_cb=(finished_cb,), + failed_cb=(finished_cb,)) + + # papyon.event.ContactEventInterface + def on_contact_memberships_changed(self, contact): + handle = ButterflyHandleFactory(self._conn_ref(), 'contact', + contact.account, contact.network_id) + if contact.is_member(papyon.Membership.FORWARD): + self.MembersChanged('', [handle], (), (), (), 0, + telepathy.CHANNEL_GROUP_CHANGE_REASON_INVITED) + if len(handle.pending_groups) > 0: + ab = self._conn.msn_client.address_book + for group in handle.pending_groups: + ab.add_contact_to_group(group, contact) + handle.pending_groups = set() + +# +#class ButterflyPublishListChannel(ButterflyListChannel, +# papyon.event.ContactEventInterface): +# +# def __init__(self, connection, manager, props): +# ButterflyListChannel.__init__(self, connection, manager, props) +# papyon.event.ContactEventInterface.__init__(self, connection.msn_client) +# self.GroupFlagsChanged(0, 0) +# +# def AddMembers(self, contacts, message): +# for handle_id in contacts: +# self._add(handle_id, message) +# +# def RemoveMembers(self, contacts, message): +# for handle_id in contacts: +# self._remove(handle_id) +# +# def GetLocalPendingMembersWithInfo(self): +# result = [] +# for contact in self._conn.msn_client.address_book.contacts: +# if not contact.is_member(papyon.Membership.PENDING): +# continue +# handle = ButterflyHandleFactory(self._conn_ref(), 'contact', +# contact.account, contact.network_id) +# result.append((handle, handle, +# telepathy.CHANNEL_GROUP_CHANGE_REASON_INVITED, +# contact.attributes.get('invite_message', ''))) +# return result +# +# def _filter_contact(self, contact): +# return (contact.is_member(papyon.Membership.ALLOW), +# contact.is_member(papyon.Membership.PENDING), +# False) +# +# @Lockable(mutex, 'add_publish', 'finished_cb') +# def _add(self, handle_id, message, finished_cb): +# handle = self._conn.handle(telepathy.HANDLE_TYPE_CONTACT, handle_id) +# contact = handle.contact +# if contact is not None and contact.is_member(papyon.Membership.ALLOW): +# return True +# +# account = handle.account +# network = handle.network +# ab = self._conn.msn_client.address_book +# if contact is not None and contact.is_member(papyon.Membership.PENDING): +# ab.accept_contact_invitation(contact, False, +# done_cb=(finished_cb,), failed_cb=(finished_cb,)) +# else: +# ab.allow_contact(account, network, +# done_cb=(finished_cb,), failed_cb=(finished_cb,)) +# +# @Lockable(mutex, 'rem_publish', 'finished_cb') +# def _remove(self, handle_id, finished_cb): +# handle = self._conn.handle(telepathy.HANDLE_TYPE_CONTACT, handle_id) +# contact = handle.contact +# ab = self._conn.msn_client.address_book +# if contact.is_member(papyon.Membership.PENDING): +# ab.decline_contact_invitation(contact, False, done_cb=finished_cb, +# failed_cb=finished_cb) +# elif contact.is_member(papyon.Membership.ALLOW): +# ab.disallow_contact(contact, done_cb=(finished_cb,), +# failed_cb=(finished_cb,)) +# else: +# return True +# +# # papyon.event.ContactEventInterface +# def on_contact_memberships_changed(self, contact): +# handle = ButterflyHandleFactory(self._conn_ref(), 'contact', +# contact.account, contact.network_id) +# if self._contains_handle(handle): +# if contact.is_member(papyon.Membership.PENDING): +# # Nothing worth our attention +# return +# +# if contact.is_member(papyon.Membership.ALLOW): +# # Contact accepted +# self.MembersChanged('', [handle], (), (), (), 0, +# telepathy.CHANNEL_GROUP_CHANGE_REASON_INVITED) +# else: +# # Contact rejected +# self.MembersChanged('', (), [handle], (), (), 0, +# telepathy.CHANNEL_GROUP_CHANGE_REASON_NONE) diff --git a/sunshine/channel/group.py b/sunshine/channel/group.py new file mode 100644 index 0000000..6094092 --- /dev/null +++ b/sunshine/channel/group.py @@ -0,0 +1,223 @@ +# telepathy-sunshine is the GaduGadu connection manager for Telepathy +# +# Copyright (C) 2006-2007 Ali Sabil <ali.sabil@gmail.com> +# Copyright (C) 2007 Johann Prieur <johann.prieur@gmail.com> +# Copyright (C) 2010 Krzysztof Klinikowski <kkszysiu@gmail.com> +# +# This program 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; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import logging, hashlib + +import telepathy + +import xml.etree.ElementTree as ET + +from sunshine.lqsoft.pygadu.models import GaduProfile, GaduContact, GaduContactGroup + +from sunshine.util.decorator import async +from sunshine.handle import SunshineHandleFactory +from sunshine.channel.contact_list import SunshineListChannel + +__all__ = ['SunshineGroupChannel'] + +logger = logging.getLogger('Sunshine.GroupChannel') + + +class SunshineGroupChannel(SunshineListChannel): + + def __init__(self, connection, manager, props): + self.__pending_add = [] + self.__pending_remove = [] + self.conn = connection + self.groups = {} + SunshineListChannel.__init__(self, connection, manager, props) + self.GroupFlagsChanged(telepathy.CHANNEL_GROUP_FLAG_CAN_ADD | + telepathy.CHANNEL_GROUP_FLAG_CAN_REMOVE, 0) + @async + def create_group(): + if self._handle.group is None: + name = self._handle.name + for group in self.conn.profile.groups: + if group.Name != name: + h = hashlib.md5() + h.update(name) + + group_xml = ET.Element("Group") + ET.SubElement(group_xml, "Id").text = h.hexdigest() + ET.SubElement(group_xml, "Name").text = name + ET.SubElement(group_xml, "IsExpanded").text = str('True') + ET.SubElement(group_xml, "IsRemovable").text = str('True') + + g = GaduContactGroup.from_xml(group_xml) + self.conn.profile.addGroup(g) + + for group in self.conn.profile.groups: + self.groups[group.Id] = group.Name + + for contact in self.conn.profile.contacts: + contact_groups = ET.fromstring(contact.Groups) + if contact.Groups: + for group in contact_groups.getchildren(): + if self.groups.has_key(group.text): + if self.groups[group.text] == self._handle.group.Name: + self.add_contact_to_group(self._handle.group, contact, None) + create_group() + + + def AddMembers(self, contacts, message): + for contact_handle_id in contacts: + contact_handle = self._conn.handle(telepathy.HANDLE_TYPE_CONTACT, + contact_handle_id) + logger.info("Adding contact %s to group %s" % + (unicode(contact_handle), unicode(self._handle))) + + contact = contact_handle.contact + group = self._handle.group + + self.add_contact_to_group(group, contact, contact_handle) + + + def RemoveMembers(self, contacts, message): + for contact_handle_id in contacts: + contact_handle = self._conn.handle(telepathy.HANDLE_TYPE_CONTACT, + contact_handle_id) + logger.info("Removing contact %s from pending group %s" % + (unicode(contact_handle), unicode(self._handle))) + + contact = contact_handle.contact + group = self._handle.group + + self.delete_contact_from_group(group, contact, contact_handle) + + def Close(self): + logger.debug("Deleting group %s" % self._handle.name) + del self.conn.profile.groups[self._handle.name] +# ab = self._conn.msn_client.address_book +# group = self._handle.group +# ab.delete_group(group) + +# def _filter_contact(self, contact): +# if contact.is_member(papyon.Membership.FORWARD): +# for group in contact.groups: +# if group.name.decode("utf-8") == self._handle.name: +# return (True, False, False) +# return (False, False, False) +# +# def on_addressbook_group_added(self, group): +# if group.name.decode("utf-8") == self._handle.name: +# self.AddMembers(self.__pending_add, None) +# self.__pending_add = [] +# self.RemoveMembers(self.__pending_remove, None) +# self.__pending_remove = [] +# +# def on_addressbook_group_deleted(self, group): +# if group.name.decode("utf-8") == self._handle.name: +# self.Closed() +# self._conn.remove_channel(self) +# +# def on_addressbook_group_contact_added(self, group, contact): +# group_name = group.name.decode("utf-8") +# if group_name == self._handle.name: +# handle = ButterflyHandleFactory(self._conn_ref(), 'contact', +# contact.account, contact.network_id) +# +# added = set() +# added.add(handle) +# +# self.MembersChanged('', added, (), (), (), 0, +# telepathy.CHANNEL_GROUP_CHANGE_REASON_NONE) +# +# logger.debug("Contact %s added to group %s" % +# (handle.name, group_name)) +# +# def on_addressbook_group_contact_deleted(self, group, contact): +# group_name = group.name.decode("utf-8") +# if group_name == self._handle.name: +# handle = ButterflyHandleFactory(self._conn_ref(), 'contact', +# contact.account, contact.network_id) +# +# removed = set() +# removed.add(handle) +# +# self.MembersChanged('', (), removed, (), (), 0, +# telepathy.CHANNEL_GROUP_CHANGE_REASON_NONE) +# +# logger.debug("Contact %s removed from group %s" % +# (handle.name, group_name)) +# + + @async + def add_contact_to_group(self, group, contact, contact_handle): + group_name = group.Name + if group_name == self._handle.name: + if hasattr(contact, 'uin'): + contact_uin = contact.uin + else: + contact_uin = contact_handle.name + + handle = SunshineHandleFactory(self.conn, 'contact', + contact_uin, None) + added = set() + added.add(handle) + + if group.Name and group.Id: + is_group = False + + contact_groups_xml = ET.Element("Groups") + if hasattr(contact, 'Groups'): + contact_groups = ET.fromstring(contact.Groups) + for c_group in contact_groups.getchildren(): + if c_group.text == group.Id: + is_group = True + ET.SubElement(contact_groups_xml, "GroupId").text = c_group.text + if is_group != True: + ET.SubElement(contact_groups_xml, "GroupId").text = group.Id + c_groups = ET.tostring(contact_groups_xml) + + if hasattr(contact, 'updateGroups'): + contact.updateGroups(c_groups) + else: + self.conn.pending_contacts_to_group[contact_uin] = c_groups + + self.MembersChanged('', added, (), (), (), 0, + telepathy.CHANNEL_GROUP_CHANGE_REASON_NONE) + + logger.debug("Contact %s added to group %s" % + (handle.name, group_name)) + + @async + def delete_contact_from_group(self, group, contact, contact_handle): + group_name = group.Name + if group_name == self._handle.name: + handle = SunshineHandleFactory(self.conn, 'contact', + contact.uin, None) + removed = set() + removed.add(handle) + + contact_groups_xml = ET.Element("Groups") + contact_groups = ET.fromstring(contact.Groups) + if contact.Groups: + for c_group in contact_groups.getchildren(): + if c_group.text != group.Id: + ET.SubElement(contact_groups_xml, "GroupId").text = c_group.text + c_groups = ET.tostring(contact_groups_xml) + + contact.updateGroups(c_groups) + + self.MembersChanged('', (), removed, (), (), 0, + telepathy.CHANNEL_GROUP_CHANGE_REASON_NONE) + + logger.debug("Contact %s removed from group %s" % + (handle.name, group_name)) diff --git a/sunshine/channel/text.py b/sunshine/channel/text.py new file mode 100644 index 0000000..03ccc9e --- /dev/null +++ b/sunshine/channel/text.py @@ -0,0 +1,198 @@ +# telepathy-sunshine is the GaduGadu connection manager for Telepathy +# +# Copyright (C) 2006-2007 Ali Sabil <ali.sabil@gmail.com> +# Copyright (C) 2007 Johann Prieur <johann.prieur@gmail.com> +# Copyright (C) 2010 Krzysztof Klinikowski <kkszysiu@gmail.com> +# +# This program 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; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import logging +import weakref +import time + +import telepathy + +from sunshine.util.decorator import async +from sunshine.handle import SunshineHandleFactory + +__all__ = ['SunshineTextChannel'] + +logger = logging.getLogger('Sunshine.TextChannel') + + +class SunshineTextChannel(telepathy.server.ChannelTypeText): + + def __init__(self, conn, manager, conversation, props): + _, surpress_handler, handle = manager._get_type_requested_handle(props) + self._recv_id = 0 + self._conn_ref = weakref.ref(conn) + self.conn = conn + + self.contact = handle.contact + + telepathy.server.ChannelTypeText.__init__(self, conn, manager, props) + + def Send(self, message_type, text): + if message_type == telepathy.CHANNEL_TEXT_MESSAGE_TYPE_NORMAL: + logger.info("Sending message : %s" % unicode(text)) + msg = text.encode('windows-1250') + self.conn.gadu_client.sendTo(int(self.contact.uin), str(text), str(msg)) + else: + raise telepathy.NotImplemented("Unhandled message type") + self.Sent(int(time.time()), message_type, text) + + def Close(self): + telepathy.server.ChannelTypeText.Close(self) + self.remove_from_connection() + + # Redefine GetSelfHandle since we use our own handle + # as Butterfly doesn't have channel specific handles + def GetSelfHandle(self): + return self._conn.GetSelfHandle() + + # Rededefine AcknowledgePendingMessages to remove offline messages + # from the oim box. + def AcknowledgePendingMessages(self, ids): + telepathy.server.ChannelTypeText.AcknowledgePendingMessages(self, ids) +# messages = [] +# for id in ids: +# if id in self._pending_offline_messages.keys(): +# messages.append(self._pending_offline_messages[id]) +# del self._pending_offline_messages[id] +# self._oim_box_ref().delete_messages(messages) + + # Rededefine ListPendingMessages to remove offline messages + # from the oim box. + def ListPendingMessages(self, clear): + return telepathy.server.ChannelTypeText.ListPendingMessages(self, clear) + + +# if clear: +# messages = self._pending_offline_messages.values() +# self._oim_box_ref().delete_messages(messages) +# return telepathy.server.ChannelTypeText.ListPendingMessages(self, clear) +# +# # papyon.event.ConversationEventInterface +# def on_conversation_user_joined(self, contact): +# handle = ButterflyHandleFactory(self._conn_ref(), 'contact', +# contact.account, contact.network_id) +# logger.info("User %s joined" % unicode(handle)) +# if handle not in self._members: +# self.MembersChanged('', [handle], [], [], [], +# handle, telepathy.CHANNEL_GROUP_CHANGE_REASON_INVITED) +# +# # papyon.event.ConversationEventInterface +# def on_conversation_user_left(self, contact): +# handle = ButterflyHandleFactory(self._conn_ref(), 'contact', +# contact.account, contact.network_id) +# logger.info("User %s left" % unicode(handle)) +# # There was only us and we are leaving, is it necessary? +# if len(self._members) == 1: +# self.ChatStateChanged(handle, telepathy.CHANNEL_CHAT_STATE_GONE) +# elif len(self._members) == 2: +# # Add the last user who left as the offline contact so we may still send +# # him offlines messages and destroy the conversation +# self._conversation.leave() +# self._conversation = None +# self._offline_handle = handle +# self._offline_contact = contact +# else: +# #If there is only us and a offline contact don't remove him from +# #the members since we still send him messages +# self.MembersChanged('', [], [handle], [], [], +# handle, telepathy.CHANNEL_GROUP_CHANGE_REASON_NONE) +# +# # papyon.event.ConversationEventInterface +# def on_conversation_user_typing(self, contact): +# handle = ButterflyHandleFactory(self._conn_ref(), 'contact', +# contact.account, contact.network_id) +# logger.info("User %s is typing" % unicode(handle)) +# self.ChatStateChanged(handle, telepathy.CHANNEL_CHAT_STATE_COMPOSING) +# +# # papyon.event.ConversationEventInterface +# def on_conversation_message_received(self, sender, message): +# id = self._recv_id +# timestamp = int(time.time()) +# handle = ButterflyHandleFactory(self._conn_ref(), 'contact', +# sender.account, sender.network_id) +# type = telepathy.CHANNEL_TEXT_MESSAGE_TYPE_NORMAL +# message = message.content +# logger.info("User %s sent a message" % unicode(handle)) +# self.Received(id, timestamp, handle, type, 0, message) +# self._recv_id += 1 +# +# # papyon.event.ConversationEventInterface +# def on_conversation_nudge_received(self, sender): +# id = self._recv_id +# timestamp = int(time.time()) +# handle = ButterflyHandleFactory(self._conn_ref(), 'contact', +# sender.account, sender.network_id) +# type = telepathy.CHANNEL_TEXT_MESSAGE_TYPE_ACTION +# text = unicode("sends you a nudge", "utf-8") +# logger.info("User %s sent a nudge" % unicode(handle)) +# self.Received(id, timestamp, handle, type, 0, text) +# self._recv_id += 1 +# +# # papyon.event.ContactEventInterface +# def on_contact_presence_changed(self, contact): +# handle = ButterflyHandleFactory(self._conn_ref(), 'contact', +# contact.account, contact.network_id) +# # Recreate a conversation if our contact join +# if self._offline_contact == contact and contact.presence != papyon.Presence.OFFLINE: +# logger.info('Contact %s connected, inviting him to the text channel' % unicode(contact)) +# client = self._conn_ref().msn_client +# self._conversation = papyon.Conversation(client, [contact]) +# papyon.event.ConversationEventInterface.__init__(self, self._conversation) +# self._offline_contact = None +# self._offline_handle = None +# #FIXME : I really hope there is no race condition between the time +# # the contact accept the invitation and the time we send him a message +# # Can a user refuse an invitation? what happens then? +# +# +# # Public API +# def offline_message_received(self, message): +# # @message a papyon.OfflineIM.OfflineMessage +# id = self._recv_id +# sender = message.sender +# timestamp = time.mktime(message.date.timetuple()) +# text = message.text +# +# # Map the id to the offline message so we can remove it +# # when acked by the client +# self._pending_offline_messages[id] = message +# +# handle = ButterflyHandleFactory(self._conn_ref(), 'contact', +# sender.account, sender.network_id) +# type = telepathy.CHANNEL_TEXT_MESSAGE_TYPE_NORMAL +# logger.info("User %r sent a offline message" % handle) +# self.Received(id, timestamp, handle, type, 0, text) +# +# self._recv_id += 1 +# +# @async +# def __add_initial_participants(self): +# handles = [] +# handles.append(self._conn.GetSelfHandle()) +# if self._conversation: +# for participant in self._conversation.participants: +# handle = ButterflyHandleFactory(self._conn_ref(), 'contact', +# participant.account, participant.network_id) +# handles.append(handle) +# else: +# handles.append(self._offline_handle) +# +# self.MembersChanged('', handles, [], [], [], +# 0, telepathy.CHANNEL_GROUP_CHANGE_REASON_NONE) |