Beispiel #1
0
 def start(self):
     notification_center = NotificationCenter()
     self._xmpp_subscription = XMPPSubscription(
         local_identity=self.sip_identity,
         remote_identity=self.xmpp_identity)
     notification_center.add_observer(self, sender=self._xmpp_subscription)
     self._xmpp_subscription.start()
     notification_center.post_notification('S2XPresenceHandlerDidStart',
                                           sender=self)
Beispiel #2
0
class S2XPresenceHandler(object):
    implements(IObserver)

    sip_identity = WriteOnceAttribute()
    xmpp_identity = WriteOnceAttribute()

    def __init__(self, sip_identity, xmpp_identity):
        self.ended = False
        self._sip_subscriptions = []
        self._stanza_cache = {}
        self._pidf = None
        self._xmpp_subscription = None
        self.sip_identity = sip_identity
        self.xmpp_identity = xmpp_identity

    def start(self):
        notification_center = NotificationCenter()
        self._xmpp_subscription = XMPPSubscription(local_identity=self.sip_identity, remote_identity=self.xmpp_identity)
        notification_center.add_observer(self, sender=self._xmpp_subscription)
        self._xmpp_subscription.start()
        notification_center.post_notification('S2XPresenceHandlerDidStart', sender=self)

    def end(self):
        if self.ended:
            return
        notification_center = NotificationCenter()
        if self._xmpp_subscription is not None:
            notification_center.remove_observer(self, sender=self._xmpp_subscription)
            self._xmpp_subscription.end()
            self._xmpp_subscription = None
        while self._sip_subscriptions:
            subscription = self._sip_subscriptions.pop()
            notification_center.remove_observer(self, sender=subscription)
            try:
                subscription.end()
            except SIPCoreError:
                pass
        self.ended = True
        notification_center.post_notification('S2XPresenceHandlerDidEnd', sender=self)

    def add_sip_subscription(self, subscription):
        # If s subscription is received after the handle has ended but before
        # S2XPresenceHandlerDidEnd has been processed we need to ignore it and wait for a retransmission
        # which we will handle by creating a new S2XPresenceHandler
        if self.ended:
            return
        self._sip_subscriptions.append(subscription)
        NotificationCenter().add_observer(self, sender=subscription)
        if self._xmpp_subscription.state == 'active':
            pidf_doc = self._pidf
            content_type = pidf.PIDFDocument.content_type if pidf_doc is not None else None
            try:
                subscription.accept(content_type, pidf_doc)
            except SIPCoreError, e:
                log.warning('Error accepting SIP subscription: %s' % e)
                subscription.end()
        else:
Beispiel #3
0
 def start(self):
     notification_center = NotificationCenter()
     self._xmpp_subscription = XMPPSubscription(local_identity=self.sip_identity, remote_identity=self.xmpp_identity)
     notification_center.add_observer(self, sender=self._xmpp_subscription)
     self._xmpp_subscription.start()
     notification_center.post_notification("S2XPresenceHandlerDidStart", sender=self)
Beispiel #4
0
class S2XPresenceHandler(object):
    implements(IObserver)

    sip_identity = WriteOnceAttribute()
    xmpp_identity = WriteOnceAttribute()

    def __init__(self, sip_identity, xmpp_identity):
        self.ended = False
        self._sip_subscriptions = []
        self._stanza_cache = {}
        self._pidf = None
        self._xmpp_subscription = None
        self.sip_identity = sip_identity
        self.xmpp_identity = xmpp_identity

    def start(self):
        notification_center = NotificationCenter()
        self._xmpp_subscription = XMPPSubscription(local_identity=self.sip_identity, remote_identity=self.xmpp_identity)
        notification_center.add_observer(self, sender=self._xmpp_subscription)
        self._xmpp_subscription.start()
        notification_center.post_notification("S2XPresenceHandlerDidStart", sender=self)

    def end(self):
        if self.ended:
            return
        notification_center = NotificationCenter()
        if self._xmpp_subscription is not None:
            notification_center.remove_observer(self, sender=self._xmpp_subscription)
            self._xmpp_subscription.end()
            self._xmpp_subscription = None
        while self._sip_subscriptions:
            subscription = self._sip_subscriptions.pop()
            notification_center.remove_observer(self, sender=subscription)
            try:
                subscription.end()
            except SIPCoreError:
                pass
        self.ended = True
        notification_center.post_notification("S2XPresenceHandlerDidEnd", sender=self)

    def add_sip_subscription(self, subscription):
        # If s subscription is received after the handle has ended but before
        # S2XPresenceHandlerDidEnd has been processed we need to ignore it and wait for a retransmission
        # which we will handle by creating a new S2XPresenceHandler
        if self.ended:
            return
        self._sip_subscriptions.append(subscription)
        NotificationCenter().add_observer(self, sender=subscription)
        if self._xmpp_subscription.state == "active":
            pidf_doc = self._pidf
            content_type = pidf.PIDFDocument.content_type if pidf_doc is not None else None
            subscription.accept(content_type, pidf_doc)
        else:
            subscription.accept_pending()
        if XMPPGatewayConfig.log_presence:
            log.msg(
                "SIP subscription from %s to %s added to presence flow 0x%x (%d subs)"
                % (
                    format_uri(self.sip_identity.uri, "sip"),
                    format_uri(self.xmpp_identity.uri, "xmpp"),
                    id(self),
                    len(self._sip_subscriptions),
                )
            )

    def _build_pidf(self):
        if not self._stanza_cache:
            self._pidf = None
            return None
        pidf_doc = pidf.PIDF(str(self.xmpp_identity))
        uri = next(self._stanza_cache.iterkeys())
        person = pidf.Person("PID-%s" % hashlib.md5("%s@%s" % (uri.user, uri.host)).hexdigest())
        person.activities = rpid.Activities()
        pidf_doc.add(person)
        for stanza in self._stanza_cache.itervalues():
            if not stanza.available:
                status = pidf.Status("closed")
                status.extended = "offline"
            else:
                status = pidf.Status("open")
                if stanza.show == "away":
                    status.extended = "away"
                    if "away" not in person.activities:
                        person.activities.add("away")
                elif stanza.show == "xa":
                    status.extended = "away"
                    if "away" not in person.activities:
                        person.activities.add("away")
                elif stanza.show == "dnd":
                    status.extended = "busy"
                    if "busy" not in person.activities:
                        person.activities.add("busy")
                else:
                    status.extended = "available"
            if stanza.sender.uri.resource:
                resource = encode_resource(stanza.sender.uri.resource)
            else:
                # Workaround for clients not sending the resource under certain (unknown) circumstances
                resource = hashlib.md5("%s@%s" % (uri.user, uri.host)).hexdigest()
            service_id = "SID-%s" % resource
            sip_uri = stanza.sender.uri.as_sip_uri()
            sip_uri.parameters["gr"] = resource
            sip_uri.parameters["xmpp"] = None
            contact = pidf.Contact(str(sip_uri))
            service = pidf.Service(service_id, status=status, contact=contact)
            service.add(pidf.DeviceID(resource))
            service.device_info = pidf.DeviceInfo(resource, description=stanza.sender.uri.resource)
            service.timestamp = pidf.ServiceTimestamp(stanza.timestamp)
            service.capabilities = caps.ServiceCapabilities(text=True, message=True)
            for lang, note in stanza.statuses.iteritems():
                service.notes.add(pidf.PIDFNote(note, lang=lang))
            pidf_doc.add(service)
        if not person.activities:
            person.activities = None
        self._pidf = pidf_doc.toxml()
        return self._pidf

    @run_in_twisted_thread
    def handle_notification(self, notification):
        handler = getattr(self, "_NH_%s" % notification.name, Null)
        handler(notification)

    def _NH_SIPIncomingSubscriptionDidEnd(self, notification):
        subscription = notification.sender
        notification.center.remove_observer(self, sender=subscription)
        self._sip_subscriptions.remove(subscription)
        if XMPPGatewayConfig.log_presence:
            log.msg(
                "SIP subscription from %s to %s removed from presence flow 0x%x (%d subs)"
                % (
                    format_uri(self.sip_identity.uri, "sip"),
                    format_uri(self.xmpp_identity.uri, "xmpp"),
                    id(self),
                    len(self._sip_subscriptions),
                )
            )
        if not self._sip_subscriptions:
            self.end()

    def _NH_SIPIncomingSubscriptionNotifyDidFail(self, notification):
        if XMPPGatewayConfig.log_presence:
            log.msg(
                "Sending SIP NOTIFY failed from %s to %s for presence flow 0x%x: %s (%s)"
                % (
                    format_uri(self.xmpp_identity.uri, "xmpp"),
                    format_uri(self.sip_identity.uri, "sip"),
                    id(self),
                    notification.data.code,
                    notification.data.reason,
                )
            )

    def _NH_SIPIncomingSubscriptionGotUnsubscribe(self, notification):
        if XMPPGatewayConfig.log_presence:
            log.msg(
                "SIP subscription from %s to %s was terminated by user for presence flow 1x%x (%d subs)"
                % (
                    format_uri(self.sip_identity.uri, "sip"),
                    format_uri(self.xmpp_identity.uri, "xmpp"),
                    id(self),
                    len(self._sip_subscriptions),
                )
            )

    def _NH_SIPIncomingSubscriptionGotRefreshingSubscribe(self, notification):
        if XMPPGatewayConfig.log_presence:
            log.msg(
                "SIP subscription from %s to %s was refreshed for presence flow 0x%x (%d subs)"
                % (
                    format_uri(self.sip_identity.uri, "sip"),
                    format_uri(self.xmpp_identity.uri, "xmpp"),
                    id(self),
                    len(self._sip_subscriptions),
                )
            )

    def _NH_SIPIncomingSubscriptionDidTimeout(self, notification):
        if XMPPGatewayConfig.log_presence:
            log.msg(
                "SIP subscription from %s to %s timed out for presence flow 0x%x (%d subs)"
                % (
                    format_uri(self.sip_identity.uri, "sip"),
                    format_uri(self.xmpp_identity.uri, "xmpp"),
                    id(self),
                    len(self._sip_subscriptions),
                )
            )

    def _NH_XMPPSubscriptionChangedState(self, notification):
        if notification.data.prev_state == "subscribe_sent" and notification.data.state == "active":
            pidf_doc = self._pidf
            content_type = pidf.PIDFDocument.content_type if pidf_doc is not None else None
            for subscription in (
                subscription for subscription in self._sip_subscriptions if subscription.state == "pending"
            ):
                subscription.accept(content_type, pidf_doc)

    def _NH_XMPPSubscriptionGotNotify(self, notification):
        stanza = notification.data.presence
        self._stanza_cache[stanza.sender.uri] = stanza
        stanza.timestamp = ISOTimestamp.now()  # TODO: mirror the one in the stanza, if present
        pidf_doc = self._build_pidf()
        if XMPPGatewayConfig.log_presence:
            log.msg(
                "XMPP notification from %s to %s for presence flow 0x%x"
                % (format_uri(self.xmpp_identity.uri, "xmpp"), format_uri(self.sip_identity.uri, "sip"), id(self))
            )
        for subscription in self._sip_subscriptions:
            try:
                subscription.push_content(pidf.PIDFDocument.content_type, pidf_doc)
            except SIPCoreError, e:
                if XMPPGatewayConfig.log_presence:
                    log.msg(
                        "Failed to send SIP NOTIFY from %s to %s for presence flow 0x%x: %s"
                        % (
                            format_uri(self.xmpp_identity.uri, "xmpp"),
                            format_uri(self.sip_identity.uri, "sip"),
                            id(self),
                            e,
                        )
                    )
        if not stanza.available:
            # Only inform once about this device being unavailable
            del self._stanza_cache[stanza.sender.uri]
Beispiel #5
0
class S2XPresenceHandler(object):
    implements(IObserver)

    sip_identity = WriteOnceAttribute()
    xmpp_identity = WriteOnceAttribute()

    def __init__(self, sip_identity, xmpp_identity):
        self.ended = False
        self._sip_subscriptions = []
        self._stanza_cache = {}
        self._pidf = None
        self._xmpp_subscription = None
        self.sip_identity = sip_identity
        self.xmpp_identity = xmpp_identity

    def start(self):
        notification_center = NotificationCenter()
        self._xmpp_subscription = XMPPSubscription(
            local_identity=self.sip_identity,
            remote_identity=self.xmpp_identity)
        notification_center.add_observer(self, sender=self._xmpp_subscription)
        self._xmpp_subscription.start()
        notification_center.post_notification('S2XPresenceHandlerDidStart',
                                              sender=self)

    def end(self):
        if self.ended:
            return
        notification_center = NotificationCenter()
        if self._xmpp_subscription is not None:
            notification_center.remove_observer(self,
                                                sender=self._xmpp_subscription)
            self._xmpp_subscription.end()
            self._xmpp_subscription = None
        while self._sip_subscriptions:
            subscription = self._sip_subscriptions.pop()
            notification_center.remove_observer(self, sender=subscription)
            try:
                subscription.end()
            except SIPCoreError:
                pass
        self.ended = True
        notification_center.post_notification('S2XPresenceHandlerDidEnd',
                                              sender=self)

    def add_sip_subscription(self, subscription):
        # If s subscription is received after the handle has ended but before
        # S2XPresenceHandlerDidEnd has been processed we need to ignore it and wait for a retransmission
        # which we will handle by creating a new S2XPresenceHandler
        if self.ended:
            return
        self._sip_subscriptions.append(subscription)
        NotificationCenter().add_observer(self, sender=subscription)
        if self._xmpp_subscription.state == 'active':
            pidf_doc = self._pidf
            content_type = pidf.PIDFDocument.content_type if pidf_doc is not None else None
            try:
                subscription.accept(content_type, pidf_doc)
            except SIPCoreError as e:
                log.warning('Error accepting SIP subscription: %s' % e)
                subscription.end()
        else:
            try:
                subscription.accept_pending()
            except SIPCoreError as e:
                log.warning('Error accepting SIP subscription: %s' % e)
                subscription.end()
        if XMPPGatewayConfig.log_presence:
            log.info(
                'SIP subscription from %s to %s added to presence flow 0x%x (%d subs)'
                % (format_uri(self.sip_identity.uri, 'sip'),
                   format_uri(self.xmpp_identity.uri,
                              'xmpp'), id(self), len(self._sip_subscriptions)))

    def _build_pidf(self):
        if not self._stanza_cache:
            self._pidf = None
            return None
        pidf_doc = pidf.PIDF(str(self.xmpp_identity))
        uri = next(self._stanza_cache.iterkeys())
        person = pidf.Person(
            "PID-%s" % hashlib.md5("%s@%s" % (uri.user, uri.host)).hexdigest())
        person.activities = rpid.Activities()
        pidf_doc.add(person)
        for stanza in self._stanza_cache.itervalues():
            if not stanza.available:
                status = pidf.Status('closed')
                status.extended = 'offline'
            else:
                status = pidf.Status('open')
                if stanza.show == 'away':
                    status.extended = 'away'
                    if 'away' not in person.activities:
                        person.activities.add('away')
                elif stanza.show == 'xa':
                    status.extended = 'away'
                    if 'away' not in person.activities:
                        person.activities.add('away')
                elif stanza.show == 'dnd':
                    status.extended = 'busy'
                    if 'busy' not in person.activities:
                        person.activities.add('busy')
                else:
                    status.extended = 'available'
            if stanza.sender.uri.resource:
                resource = encode_resource(stanza.sender.uri.resource)
            else:
                # Workaround for clients not sending the resource under certain (unknown) circumstances
                resource = hashlib.md5("%s@%s" %
                                       (uri.user, uri.host)).hexdigest()
            service_id = "SID-%s" % resource
            sip_uri = stanza.sender.uri.as_sip_uri()
            sip_uri.parameters['gr'] = resource
            sip_uri.parameters['xmpp'] = None
            contact = pidf.Contact(str(sip_uri))
            service = pidf.Service(service_id, status=status, contact=contact)
            service.add(pidf.DeviceID(resource))
            service.device_info = pidf.DeviceInfo(
                resource, description=stanza.sender.uri.resource)
            service.timestamp = pidf.ServiceTimestamp(stanza.timestamp)
            service.capabilities = caps.ServiceCapabilities(text=True,
                                                            message=True)
            for lang, note in stanza.statuses.iteritems():
                service.notes.add(pidf.PIDFNote(note, lang=lang))
            pidf_doc.add(service)
        if not person.activities:
            person.activities = None
        self._pidf = pidf_doc.toxml()
        return self._pidf

    @run_in_twisted_thread
    def handle_notification(self, notification):
        handler = getattr(self, '_NH_%s' % notification.name, Null)
        handler(notification)

    def _NH_SIPIncomingSubscriptionDidEnd(self, notification):
        subscription = notification.sender
        notification.center.remove_observer(self, sender=subscription)
        self._sip_subscriptions.remove(subscription)
        if XMPPGatewayConfig.log_presence:
            log.info(
                'SIP subscription from %s to %s removed from presence flow 0x%x (%d subs)'
                % (format_uri(self.sip_identity.uri, 'sip'),
                   format_uri(self.xmpp_identity.uri,
                              'xmpp'), id(self), len(self._sip_subscriptions)))
        if not self._sip_subscriptions:
            self.end()

    def _NH_SIPIncomingSubscriptionNotifyDidFail(self, notification):
        if XMPPGatewayConfig.log_presence:
            log.info(
                'Sending SIP NOTIFY failed from %s to %s for presence flow 0x%x: %s (%s)'
                % (format_uri(self.xmpp_identity.uri, 'xmpp'),
                   format_uri(self.sip_identity.uri, 'sip'), id(self),
                   notification.data.code, notification.data.reason))

    def _NH_SIPIncomingSubscriptionGotUnsubscribe(self, notification):
        if XMPPGatewayConfig.log_presence:
            log.info(
                'SIP subscription from %s to %s was terminated by user for presence flow 1x%x (%d subs)'
                % (format_uri(self.sip_identity.uri, 'sip'),
                   format_uri(self.xmpp_identity.uri,
                              'xmpp'), id(self), len(self._sip_subscriptions)))

    def _NH_SIPIncomingSubscriptionGotRefreshingSubscribe(self, notification):
        if XMPPGatewayConfig.log_presence:
            log.info(
                'SIP subscription from %s to %s was refreshed for presence flow 0x%x (%d subs)'
                % (format_uri(self.sip_identity.uri, 'sip'),
                   format_uri(self.xmpp_identity.uri,
                              'xmpp'), id(self), len(self._sip_subscriptions)))

    def _NH_SIPIncomingSubscriptionDidTimeout(self, notification):
        if XMPPGatewayConfig.log_presence:
            log.info(
                'SIP subscription from %s to %s timed out for presence flow 0x%x (%d subs)'
                % (format_uri(self.sip_identity.uri, 'sip'),
                   format_uri(self.xmpp_identity.uri,
                              'xmpp'), id(self), len(self._sip_subscriptions)))

    def _NH_XMPPSubscriptionChangedState(self, notification):
        if notification.data.prev_state == 'subscribe_sent' and notification.data.state == 'active':
            pidf_doc = self._pidf
            content_type = pidf.PIDFDocument.content_type if pidf_doc is not None else None
            for subscription in (subscription
                                 for subscription in self._sip_subscriptions
                                 if subscription.state == 'pending'):
                subscription.accept(content_type, pidf_doc)

    def _NH_XMPPSubscriptionGotNotify(self, notification):
        stanza = notification.data.presence
        self._stanza_cache[stanza.sender.uri] = stanza
        stanza.timestamp = ISOTimestamp.now(
        )  # TODO: mirror the one in the stanza, if present
        pidf_doc = self._build_pidf()
        if XMPPGatewayConfig.log_presence:
            log.info('XMPP notification from %s to %s for presence flow 0x%x' %
                     (format_uri(self.xmpp_identity.uri, 'xmpp'),
                      format_uri(self.sip_identity.uri, 'sip'), id(self)))
        for subscription in self._sip_subscriptions:
            try:
                subscription.push_content(pidf.PIDFDocument.content_type,
                                          pidf_doc)
            except SIPCoreError as e:
                if XMPPGatewayConfig.log_presence:
                    log.info(
                        'Failed to send SIP NOTIFY from %s to %s for presence flow 0x%x: %s'
                        % (format_uri(self.xmpp_identity.uri, 'xmpp'),
                           format_uri(self.sip_identity.uri,
                                      'sip'), id(self), e))
        if not stanza.available:
            # Only inform once about this device being unavailable
            del self._stanza_cache[stanza.sender.uri]

    def _NH_XMPPSubscriptionDidFail(self, notification):
        notification.center.remove_observer(self,
                                            sender=self._xmpp_subscription)
        self._xmpp_subscription = None
        self.end()

    _NH_XMPPSubscriptionDidEnd = _NH_XMPPSubscriptionDidFail