diff --git a/sylk/applications/ircconference/__init__.py b/sylk/applications/ircconference/__init__.py index ec96ed2..11fcbc8 100644 --- a/sylk/applications/ircconference/__init__.py +++ b/sylk/applications/ircconference/__init__.py @@ -1,92 +1,92 @@ # Copyright (C) 2011 AG Projects. See LICENSE for details # from application import log from application.notification import IObserver, NotificationCenter from application.python.util import Null, Singleton from twisted.internet import reactor from zope.interface import implements from sylk.applications import ISylkApplication, sylk_application from sylk.applications.ircconference.room import IRCRoom @sylk_application class IRCConferenceApplication(object): __metaclass__ = Singleton implements(ISylkApplication, IObserver) __appname__ = 'irc-conference' def __init__(self): self.rooms = set() self.pending_sessions = [] def incoming_session(self, session): log.msg('New incoming session from %s' % session.remote_identity.uri) try: chat_stream = (stream for stream in session.proposed_streams if stream.type=='chat').next() except StopIteration: session.reject(488) return # Disable private message capability - chat_stream.focus_capabilities = [] + chat_stream.chatroom_capabilities = [] self.pending_sessions.append(session) notification_center = NotificationCenter() notification_center.add_observer(self, sender=session) reactor.callLater(0, self.accept_session, session, [chat_stream]) def incoming_subscription(self, subscribe_request, data): to_header = data.headers.get('To', Null) if to_header is Null: subscribe_request.reject(400) return room = IRCRoom.get_room(data.request_uri) if not room.started: room = IRCRoom.get_room(to_header.uri) if not room.started: subscribe_request.reject(480) return room.handle_incoming_subscription(subscribe_request, data) def incoming_sip_message(self, message_request, data): pass def accept_session(self, session, streams): if session in self.pending_sessions: session.accept(streams, is_focus=True) def handle_notification(self, notification): handler = getattr(self, '_NH_%s' % notification.name, Null) handler(notification) def _NH_SIPSessionDidStart(self, notification): session = notification.sender self.pending_sessions.remove(session) room = IRCRoom.get_room(session._invitation.request_uri) # FIXME room.start() room.add_session(session) self.rooms.add(room) def _NH_SIPSessionDidEnd(self, notification): session = notification.sender log.msg('Session from %s ended' % session.remote_identity.uri) notification_center = NotificationCenter() notification_center.remove_observer(self, sender=session) room = IRCRoom.get_room(session._invitation.request_uri) # FIXME if session in room.sessions: # We could get this notifiction even if we didn't get SIPSessionDidStart room.remove_session(session) if room.empty: room.stop() try: self.rooms.remove(room) except KeyError: pass def _NH_SIPSessionDidFail(self, notification): session = notification.sender self.pending_sessions.remove(session) log.msg('Session from %s failed' % session.remote_identity.uri) diff --git a/sylk/extensions.py b/sylk/extensions.py index fbfe9b9..f1c3ad8 100644 --- a/sylk/extensions.py +++ b/sylk/extensions.py @@ -1,74 +1,74 @@ # Copyright (C) 2010-2011 AG Projects. See LICENSE for details. # import random from datetime import datetime from msrplib.session import contains_mime_type from sipsimple.account import AccountManager from sipsimple.core import SDPAttribute from sipsimple.payloads.iscomposing import IsComposingMessage, State, LastActive, Refresh, ContentType from sipsimple.streams import MediaStreamRegistry from sipsimple.streams.applications.chat import CPIMMessage from sipsimple.streams.msrp import ChatStream as _ChatStream, ChatStreamError, MSRPStreamBase # We need to match on the only account that will be available def _always_find_default_account(self, contact_uri): return self.default_account AccountManager.find_account = _always_find_default_account # We need to be able to set the local identity in the message CPIM envelope # so that messages appear to be coming from the users themselves, instead of # just seeying the server identity registry = MediaStreamRegistry() for stream_type in registry.stream_types[:]: if stream_type is _ChatStream: registry.stream_types.remove(stream_type) break del registry class ChatStream(_ChatStream): accept_types = ['message/cpim'] accept_wrapped_types = ['*'] - focus_capabilities = [('chatroom', 'private-messages')] + chatroom_capabilities = ['private-messages'] def _create_local_media(self, uri_path): local_media = MSRPStreamBase._create_local_media(self, uri_path) - if self.session.local_focus: - local_media.attributes.extend(SDPAttribute(item[0], item[1]) for item in self.focus_capabilities) + if self.session.local_focus and self.chatroom_capabilities: + local_media.attributes.append(SDPAttribute('chatroom', ' '.join(self.chatroom_capabilities))) return local_media def send_message(self, content, content_type='text/plain', local_identity=None, recipients=None, courtesy_recipients=None, subject=None, timestamp=None, required=None, additional_headers=None): if self.direction=='recvonly': raise ChatStreamError('Cannot send message on recvonly stream') message_id = '%x' % random.getrandbits(64) if not contains_mime_type(self.accept_wrapped_types, content_type): raise ChatStreamError('Invalid content_type for outgoing message: %r' % content_type) if not recipients: recipients = [self.remote_identity] if timestamp is None: timestamp = datetime.now() # Only use CPIM, it's the only type we accept msg = CPIMMessage(content, content_type, sender=local_identity or self.local_identity, recipients=recipients, courtesy_recipients=courtesy_recipients, subject=subject, timestamp=timestamp, required=required, additional_headers=additional_headers) self._enqueue_message(message_id, str(msg), 'message/cpim', failure_report='yes', success_report='yes', notify_progress=True) return message_id def send_composing_indication(self, state, refresh, last_active=None, recipients=None, local_identity=None): if self.direction == 'recvonly': raise ChatStreamError('Cannot send message on recvonly stream') if state not in ('active', 'idle'): raise ValueError('Invalid value for composing indication state') message_id = '%x' % random.getrandbits(64) content = IsComposingMessage(state=State(state), refresh=Refresh(refresh), last_active=LastActive(last_active or datetime.now()), content_type=ContentType('text')).toxml() if recipients is None: recipients = [self.remote_identity] # Only use CPIM, it's the only type we accept msg = CPIMMessage(content, IsComposingMessage.content_type, sender=local_identity or self.local_identity, recipients=recipients, timestamp=datetime.now()) self._enqueue_message(message_id, str(msg), 'message/cpim', failure_report='partial', success_report='no') return message_id