diff options
Diffstat (limited to 'plugins/whiteboard/plugin.py')
-rw-r--r-- | plugins/whiteboard/plugin.py | 483 |
1 files changed, 0 insertions, 483 deletions
diff --git a/plugins/whiteboard/plugin.py b/plugins/whiteboard/plugin.py deleted file mode 100644 index 9132e9a88..000000000 --- a/plugins/whiteboard/plugin.py +++ /dev/null @@ -1,483 +0,0 @@ -## plugins/whiteboard/plugin.py -## -## Copyright (C) 2009 Jeff Ling <jeff.ummu AT gmail.com> -## Copyright (C) 2010 Yann Leboulanger <asterix AT lagaule.org> -## -## 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/>. -## - -''' -Whiteboard plugin. - -:author: Yann Leboulanger <asterix@lagaule.org> -:since: 1st November 2010 -:copyright: Copyright (2010) Yann Leboulanger <asterix@lagaule.org> -:license: GPL -''' - - -from common import helpers -from common import gajim -from plugins import GajimPlugin -from plugins.plugin import GajimPluginException -from plugins.helpers import log_calls, log -import common.xmpp -import gtk -import chat_control -from common import ged -from common.jingle_session import JingleSession -from common.jingle_content import JingleContent -from common.jingle_transport import JingleTransport, TransportType -import dialogs -from whiteboard_widget import Whiteboard, HAS_GOOCANVAS -from common import xmpp -from common import caps_cache - -NS_JINGLE_XHTML = 'urn:xmpp:tmp:jingle:apps:xhtml' -NS_JINGLE_SXE = 'urn:xmpp:tmp:jingle:transports:sxe' -NS_SXE = 'urn:xmpp:sxe:0' - -class WhiteboardPlugin(GajimPlugin): - @log_calls('WhiteboardPlugin') - def init(self): - self.description = _('Shows a whiteboard in chat.' - ' python-pygoocanvas is required.') - self.config_dialog = None - self.events_handlers = { - 'jingle-request-received': (ged.GUI1, self._nec_jingle_received), - 'jingle-connected-received': (ged.GUI1, self._nec_jingle_connected), - 'jingle-disconnected-received': (ged.GUI1, - self._nec_jingle_disconnected), - 'raw-message-received': (ged.GUI1, self._nec_raw_message), - } - self.gui_extension_points = { - 'chat_control_base' : (self.connect_with_chat_control, - self.disconnect_from_chat_control), - 'chat_control_base_update_toolbar': (self.update_button_state, - None), - } - self.controls = [] - self.sid = None - - @log_calls('WhiteboardPlugin') - def _compute_caps_hash(self): - for a in gajim.connections: - gajim.caps_hash[a] = caps_cache.compute_caps_hash([ - gajim.gajim_identity], gajim.gajim_common_features + \ - gajim.gajim_optional_features[a]) - # re-send presence with new hash - connected = gajim.connections[a].connected - if connected > 1 and gajim.SHOW_LIST[connected] != 'invisible': - gajim.connections[a].change_status(gajim.SHOW_LIST[connected], - gajim.connections[a].status) - - @log_calls('WhiteboardPlugin') - def activate(self): - if not HAS_GOOCANVAS: - raise GajimPluginException('python-pygoocanvas is missing!') - if NS_JINGLE_SXE not in gajim.gajim_common_features: - gajim.gajim_common_features.append(NS_JINGLE_SXE) - if NS_SXE not in gajim.gajim_common_features: - gajim.gajim_common_features.append(NS_SXE) - self._compute_caps_hash() - - @log_calls('WhiteboardPlugin') - def deactivate(self): - if NS_JINGLE_SXE in gajim.gajim_common_features: - gajim.gajim_common_features.remove(NS_JINGLE_SXE) - if NS_SXE in gajim.gajim_common_features: - gajim.gajim_common_features.remove(NS_SXE) - self._compute_caps_hash() - - @log_calls('WhiteboardPlugin') - def connect_with_chat_control(self, control): - if isinstance(control, chat_control.ChatControl): - base = Base(self, control) - self.controls.append(base) - - @log_calls('WhiteboardPlugin') - def disconnect_from_chat_control(self, chat_control): - for base in self.controls: - base.disconnect_from_chat_control() - self.controls = [] - - @log_calls('WhiteboardPlugin') - def update_button_state(self, control): - for base in self.controls: - if base.chat_control == control: - if control.contact.supports(NS_JINGLE_SXE) and \ - control.contact.supports(NS_SXE): - base.button.set_sensitive(True) - tooltip_text = _('Show whiteboard') - else: - base.button.set_sensitive(False) - tooltip_text = _('Client on the other side ' - 'does not support the whiteboard') - base.button.set_tooltip_text(tooltip_text) - - @log_calls('WhiteboardPlugin') - def show_request_dialog(self, account, fjid, jid, sid, content_types): - def on_ok(): - session = gajim.connections[account].get_jingle_session(fjid, sid) - self.sid = session.sid - if not session.accepted: - session.approve_session() - for content in content_types: - session.approve_content(content) - for _jid in (fjid, jid): - ctrl = gajim.interface.msg_win_mgr.get_control(_jid, account) - if ctrl: - break - if not ctrl: - # create it - gajim.interface.new_chat_from_jid(account, jid) - ctrl = gajim.interface.msg_win_mgr.get_control(jid, account) - session = session.contents[('initiator', 'xhtml')] - ctrl.draw_whiteboard(session) - - def on_cancel(): - session = gajim.connections[account].get_jingle_session(fjid, sid) - session.decline_session() - - contact = gajim.contacts.get_first_contact_from_jid(account, jid) - if contact: - name = contact.get_shown_name() - else: - name = jid - pritext = _('Incoming Whiteboard') - sectext = _('%(name)s (%(jid)s) wants to start a whiteboard with ' - 'you. Do you want to accept?') % {'name': name, 'jid': jid} - dialog = dialogs.NonModalConfirmationDialog(pritext, sectext=sectext, - on_response_ok=on_ok, on_response_cancel=on_cancel) - dialog.popup() - - @log_calls('WhiteboardPlugin') - def _nec_jingle_received(self, obj): - if not HAS_GOOCANVAS: - return - content_types = set(c[0] for c in obj.contents) - if 'xhtml' not in content_types: - return - self.show_request_dialog(obj.conn.name, obj.fjid, obj.jid, obj.sid, - content_types) - - @log_calls('WhiteboardPlugin') - def _nec_jingle_connected(self, obj): - if not HAS_GOOCANVAS: - return - account = obj.conn.name - ctrl = (gajim.interface.msg_win_mgr.get_control(obj.fjid, account) - or gajim.interface.msg_win_mgr.get_control(obj.jid, account)) - if not ctrl: - return - session = gajim.connections[obj.conn.name].get_jingle_session(obj.fjid, - obj.sid) - - if ('initiator', 'xhtml') not in session.contents: - return - - session = session.contents[('initiator', 'xhtml')] - ctrl.draw_whiteboard(session) - - @log_calls('WhiteboardPlugin') - def _nec_jingle_disconnected(self, obj): - for base in self.controls: - if base.sid == obj.sid: - base.stop_whiteboard(reason = obj.reason) - - @log_calls('WhiteboardPlugin') - def _nec_raw_message(self, obj): - if not HAS_GOOCANVAS: - return - if obj.stanza.getTag('sxe', namespace=NS_SXE): - account = obj.conn.name - - try: - fjid = helpers.get_full_jid_from_iq(obj.stanza) - except helpers.InvalidFormat: - obj.conn.dispatch('ERROR', (_('Invalid Jabber ID'), - _('A message from a non-valid JID arrived, it has been ' - 'ignored.'))) - - jid = gajim.get_jid_without_resource(fjid) - ctrl = (gajim.interface.msg_win_mgr.get_control(fjid, account) - or gajim.interface.msg_win_mgr.get_control(jid, account)) - if not ctrl: - return - sxe = obj.stanza.getTag('sxe') - if not sxe: - return - sid = sxe.getAttr('session') - if (jid, sid) not in obj.conn._sessions: - pass -# newjingle = JingleSession(con=self, weinitiate=False, jid=jid, sid=sid) -# self.addJingle(newjingle) - - # we already have such session in dispatcher... - session = obj.conn.get_jingle_session(fjid, sid) - cn = session.contents[('initiator', 'xhtml')] - error = obj.stanza.getTag('error') - if error: - action = 'iq-error' - else: - action = 'edit' - - cn.on_stanza(obj.stanza, sxe, error, action) -# def __editCB(self, stanza, content, error, action): - #new_tags = sxe.getTags('new') - #remove_tags = sxe.getTags('remove') - - #if new_tags is not None: - ## Process new elements - #for tag in new_tags: - #if tag.getAttr('type') == 'element': - #ctrl.whiteboard.recieve_element(tag) - #elif tag.getAttr('type') == 'attr': - #ctrl.whiteboard.recieve_attr(tag) - #ctrl.whiteboard.apply_new() - - #if remove_tags is not None: - ## Delete rids - #for tag in remove_tags: - #target = tag.getAttr('target') - #ctrl.whiteboard.image.del_rid(target) - - # Stop propagating this event, it's handled - return True - - -class Base(object): - def __init__(self, plugin, chat_control): - self.plugin = plugin - self.chat_control = chat_control - self.chat_control.draw_whiteboard = self.draw_whiteboard - self.contact = self.chat_control.contact - self.account = self.chat_control.account - self.jid = self.contact.get_full_jid() - self.create_buttons() - self.whiteboard = None - self.sid = None - - def create_buttons(self): - # create whiteboard button - actions_hbox = self.chat_control.xml.get_object('actions_hbox') - self.button = gtk.ToggleButton(label=None, use_underline=True) - self.button.set_property('relief', gtk.RELIEF_NONE) - self.button.set_property('can-focus', False) - img = gtk.Image() - img_path = self.plugin.local_file_path('whiteboard.png') - pixbuf = gtk.gdk.pixbuf_new_from_file(img_path) - iconset = gtk.IconSet(pixbuf=pixbuf) - factory = gtk.IconFactory() - factory.add('whiteboard', iconset) - img_path = self.plugin.local_file_path('brush_tool.png') - pixbuf = gtk.gdk.pixbuf_new_from_file(img_path) - iconset = gtk.IconSet(pixbuf=pixbuf) - factory.add('brush_tool', iconset) - img_path = self.plugin.local_file_path('line_tool.png') - pixbuf = gtk.gdk.pixbuf_new_from_file(img_path) - iconset = gtk.IconSet(pixbuf=pixbuf) - factory.add('line_tool', iconset) - img_path = self.plugin.local_file_path('oval_tool.png') - pixbuf = gtk.gdk.pixbuf_new_from_file(img_path) - iconset = gtk.IconSet(pixbuf=pixbuf) - factory.add('oval_tool', iconset) - factory.add_default() - img.set_from_stock('whiteboard', gtk.ICON_SIZE_MENU) - self.button.set_image(img) - send_button = self.chat_control.xml.get_object('send_button') - send_button_pos = actions_hbox.child_get_property(send_button, - 'position') - actions_hbox.add_with_properties(self.button, 'position', - send_button_pos - 1, 'expand', False) - id_ = self.button.connect('toggled', self.on_whiteboard_button_toggled) - self.chat_control.handlers[id_] = self.button - self.button.show() - - def draw_whiteboard(self, content): - hbox = self.chat_control.xml.get_object('chat_control_hbox') - if len(hbox.get_children()) == 1: - self.whiteboard = Whiteboard(self.account, self.contact, content, - self.plugin) - # set minimum size - self.whiteboard.hbox.set_size_request(300, 0) - hbox.pack_start(self.whiteboard.hbox, expand=False, fill=False) - self.whiteboard.hbox.show_all() - self.button.set_active(True) - content.control = self - self.sid = content.session.sid - - def on_whiteboard_button_toggled(self, widget): - """ - Popup whiteboard - """ - if widget.get_active(): - if not self.whiteboard: - self.start_whiteboard() - else: - self.stop_whiteboard() - - def start_whiteboard(self): - conn = gajim.connections[self.chat_control.account] - jingle = JingleSession(conn, weinitiate=True, jid=self.jid) - self.sid = jingle.sid - conn._sessions[jingle.sid] = jingle - content = JingleWhiteboard(jingle) - content.control = self - jingle.add_content('xhtml', content) - jingle.start_session() - - def stop_whiteboard(self, reason=None): - conn = gajim.connections[self.chat_control.account] - self.sid = None - session = conn.get_jingle_session(self.jid, media='xhtml') - if session: - session.end_session() - self.button.set_active(False) - if reason: - txt = _('Whiteboard stopped: %(reason)s') % {'reason': reason} - self.chat_control.print_conversation(txt, 'info') - if not self.whiteboard: - return - hbox = self.chat_control.xml.get_object('chat_control_hbox') - if self.whiteboard.hbox in hbox.get_children(): - if hasattr(self.whiteboard, 'hbox'): - hbox.remove(self.whiteboard.hbox) - self.whiteboard = None - - def disconnect_from_chat_control(self): - actions_hbox = self.chat_control.xml.get_object('actions_hbox') - actions_hbox.remove(self.button) - -class JingleWhiteboard(JingleContent): - ''' Jingle Whiteboard sessions consist of xhtml content''' - def __init__(self, session, transport=None): - if not transport: - transport = JingleTransportSXE() - JingleContent.__init__(self, session, transport) - self.media = 'xhtml' - self.negotiated = True # there is nothing to negotiate - self.last_rid = 0 - self.callbacks['session-accept'] += [self._sessionAcceptCB] - self.callbacks['session-terminate'] += [self._stop] - self.callbacks['session-terminate-sent'] += [self._stop] - self.callbacks['edit'] = [self._EditCB] - - def _EditCB(self, stanza, content, error, action): - new_tags = content.getTags('new') - remove_tags = content.getTags('remove') - - if new_tags is not None: - # Process new elements - for tag in new_tags: - if tag.getAttr('type') == 'element': - self.control.whiteboard.recieve_element(tag) - elif tag.getAttr('type') == 'attr': - self.control.whiteboard.recieve_attr(tag) - self.control.whiteboard.apply_new() - - if remove_tags is not None: - # Delete rids - for tag in remove_tags: - target = tag.getAttr('target') - self.control.whiteboard.image.del_rid(target) - - def _sessionAcceptCB(self, stanza, content, error, action): - log.debug('session accepted') - self.session.connection.dispatch('WHITEBOARD_ACCEPTED', - (self.session.peerjid, self.session.sid)) - - def generate_rids(self, x): - # generates x number of rids and returns in list - rids = [] - for x in range(x): - rids.append(str(self.last_rid)) - self.last_rid += 1 - return rids - - def send_whiteboard_node(self, items, rids): - # takes int rid and dict items and sends it as a node - # sends new item - jid = self.session.peerjid - sid = self.session.sid - message = xmpp.Message(to=jid) - sxe = message.addChild(name='sxe', attrs={'session': sid}, - namespace=NS_SXE) - - for x in rids: - if items[x]['type'] == 'element': - parent = x - attrs = {'rid': x, - 'name': items[x]['data'][0].getName(), - 'type': items[x]['type']} - sxe.addChild(name='new', attrs=attrs) - if items[x]['type'] == 'attr': - attr_name = items[x]['data'] - chdata = items[parent]['data'][0].getAttr(attr_name) - attrs = {'rid': x, - 'name': attr_name, - 'type': items[x]['type'], - 'chdata': chdata, - 'parent': parent} - sxe.addChild(name='new', attrs=attrs) - self.session.connection.connection.send(message) - - def delete_whiteboard_node(self, rids): - message = xmpp.Message(to=self.session.peerjid) - sxe = message.addChild(name='sxe', attrs={'session': self.session.sid}, - namespace=NS_SXE) - - for x in rids: - sxe.addChild(name='remove', attrs = {'target': x}) - self.session.connection.connection.send(message) - - def send_items(self, items, rids): - # recieves dict items and a list of rids of items to send - # TODO: is there a less clumsy way that doesn't involve passing - # whole list - self.send_whiteboard_node(items, rids) - - def del_item(self, rids): - self.delete_whiteboard_node(rids) - - def encode(self, xml): - # encodes it sendable string - return 'data:text/xml,' + urllib.quote(xml) - - def _fill_content(self, content): - content.addChild(NS_JINGLE_XHTML + ' description') - - def _stop(self, *things): - pass - - def __del__(self): - pass - -def get_content(desc): - return JingleWhiteboard - -common.jingle_content.contents[NS_JINGLE_XHTML] = get_content - -class JingleTransportSXE(JingleTransport): - def __init__(self): - JingleTransport.__init__(self, TransportType.streaming) - - def make_transport(self, candidates=None): - transport = JingleTransport.make_transport(self, candidates) - transport.setNamespace(NS_JINGLE_SXE) - transport.setTagData('host', 'TODO') - return transport - -common.jingle_transport.transports[NS_JINGLE_SXE] = JingleTransportSXE |