예제 #1
0
    def create(self, transferred_call, initiator_call, context, exten, flow,
               variables, timeout):
        try:
            transferred_channel = self.ari.channels.get(
                channelId=transferred_call)
            initiator_channel = self.ari.channels.get(channelId=initiator_call)
        except ARINotFound:
            raise TransferCreationError('channel not found')

        if not ami.extension_exists(self.amid_client, context, exten):
            raise InvalidExtension(context, exten)

        if not self.transfer_lock.acquire(initiator_call):
            raise TransferAlreadyStarted(initiator_call)

        if not (Channel(transferred_call, self.ari).is_in_stasis()
                and Channel(initiator_call, self.ari).is_in_stasis()):
            transfer_state = self.state_factory.make_from_class(
                TransferStateReadyNonStasis)
        else:
            transfer_state = self.state_factory.make_from_class(
                TransferStateReady)

        try:
            new_state = transfer_state.create(transferred_channel,
                                              initiator_channel, context,
                                              exten, variables, timeout)
        except Exception:
            self.transfer_lock.release(initiator_call)
            raise
        if flow == 'blind':
            new_state = new_state.complete()

        return new_state.transfer
예제 #2
0
    def create_from_user(self, initiator_call, exten, flow, timeout,
                         user_uuid):
        if not Channel(initiator_call, self.ari).exists():
            raise TransferCreationError('initiator channel not found')

        if Channel(initiator_call, self.ari).user() != user_uuid:
            raise UserPermissionDenied(user_uuid, {'call': initiator_call})

        try:
            transferred_call = Channel(initiator_call,
                                       self.ari).only_connected_channel().id
        except TooManyChannels as e:
            raise TooManyTransferredCandidates(e.channels)
        except NotEnoughChannels as e:
            raise TransferCreationError('transferred channel not found')

        context = User(user_uuid, self.confd_client).main_line().context()

        return self.create(transferred_call,
                           initiator_call,
                           context,
                           exten,
                           flow,
                           variables={},
                           timeout=timeout)
예제 #3
0
    def hangup_user(self, call_id, user_uuid):
        channel = Channel(call_id, self._ari)
        if not channel.exists() or channel.is_local():
            raise NoSuchCall(call_id)

        if channel.user() != user_uuid:
            raise UserPermissionDenied(user_uuid, {'call': call_id})

        self._ari.channels.hangup(channelId=call_id)
예제 #4
0
    def create(self, transferred_channel, initiator_channel, context, exten, variables, timeout):
        initiator_uuid = Channel(initiator_channel.id, self._ari).user()
        if initiator_uuid is None:
            raise TransferCreationError('initiator has no user UUID')

        transfer_id = str(uuid.uuid4())
        try:
            ari_helpers.convert_transfer_to_stasis(self._ari,
                                                   self._amid,
                                                   transferred_channel.id,
                                                   initiator_channel.id,
                                                   context,
                                                   exten,
                                                   transfer_id,
                                                   variables,
                                                   timeout)
        except ARINotFound:
            raise TransferCreationError('channel not found')
        self.transfer = Transfer(transfer_id, initiator_uuid)
        self.transfer.initiator_call = initiator_channel.id
        self.transfer.transferred_call = transferred_channel.id
        self.transfer.status = self.name
        self._notifier.created(self.transfer)

        return TransferStateStarting.from_state(self)
예제 #5
0
    def _channel_hold(self, event):
        channel_id = event['Uniqueid']
        logger.debug('marking channel %s on hold', channel_id)
        ami.set_variable_ami(self.ami, channel_id, 'XIVO_ON_HOLD', '1')

        user_uuid = Channel(channel_id, self.ari).user()
        bus_msg = CallOnHoldEvent(channel_id, user_uuid)
        self.bus_publisher.publish(bus_msg, headers={'user_uuid:{uuid}'.format(uuid=user_uuid): True})
예제 #6
0
    def process_lost_hangups(self):
        transfers = list(self.state_persistor.list())

        logger.debug('Processing lost hangups since last stop...')
        for transfer in transfers:
            transfer_state = self.state_factory.make(transfer)
            if not Channel(transfer.transferred_call, self.ari).exists():
                logger.debug('Transferred hangup from transfer %s',
                             transfer.id)
                transfer_state = transfer_state.transferred_hangup()
            if not Channel(transfer.initiator_call, self.ari).exists():
                logger.debug('Initiator hangup from transfer %s', transfer.id)
                transfer_state = transfer_state.initiator_hangup()
            if not Channel(transfer.recipient_call, self.ari).exists():
                logger.debug('Recipient hangup from transfer %s', transfer.id)
                transfer_state = transfer_state.recipient_hangup()
        logger.debug('Done.')
예제 #7
0
    def create(self,
               initiator_call,
               destination,
               location,
               completions,
               timeout,
               relocate=None):
        try:
            relocated_channel = Channel(initiator_call,
                                        self.ari).only_connected_channel()
        except TooManyChannels as e:
            raise TooManyChannelCandidates(e.channels)
        except NotEnoughChannels as e:
            raise RelocateCreationError('relocated channel not found')

        initiator_channel = Channel(initiator_call, self.ari)
        if not initiator_channel.exists():
            details = {'initiator_call': initiator_call}
            raise RelocateCreationError('initiator call not found', details)

        try:
            destination = self.destination_factory.from_type(
                destination, location)
        except InvalidDestination:
            details = {'destination': destination, 'location': location}
            raise RelocateCreationError('invalid destination', details)

        with self.duplicate_relocate_lock:
            if self.relocates.find_by_channel(initiator_channel.id):
                raise RelocateAlreadyStarted(initiator_channel.id)

            if not relocate:
                relocate = Relocate(self.state_factory)

            relocate.relocated_channel = relocated_channel.id
            relocate.initiator_channel = initiator_channel.id
            relocate.completions = completions
            relocate.timeout = timeout
            self.relocates.add(relocate)
            self.notifier.observe(relocate)

        with relocate.locked():
            relocate.initiate(destination)

        return relocate
예제 #8
0
    def make_call_from_channel(self, ari, channel):
        call = Call(channel.id)
        call.creation_time = channel.json['creationtime']
        call.status = channel.json['state']
        call.caller_id_name = channel.json['caller']['name']
        call.caller_id_number = channel.json['caller']['number']
        call.user_uuid = Channel(channel.id, ari).user()
        call.on_hold = self._get_hold_from_channel_id(ari, channel.id) == '1'
        call.bridges = [
            bridge.id for bridge in ari.bridges.list()
            if channel.id in bridge.json['channels']
        ]
        call.talking_to = {
            connected_channel.id: connected_channel.user()
            for connected_channel in Channel(channel.id,
                                             ari).connected_channels()
        }

        return call
예제 #9
0
    def complete(self, relocate):
        completer = RelocateCompleter(self._amid, self._ari)

        if Channel(relocate.relocated_channel, self._ari).is_in_stasis():
            completer.bridge(relocate)
            try:
                self._ari.channels.hangup(channelId=relocate.initiator_channel)
            except ARINotFound:
                pass
            except ARIException as e:
                logger.exception('ARI error: %s', e)
            relocate.set_state('ended')
        else:
            completer.move_to_stasis(relocate)
            relocate.set_state('waiting_for_relocated')
예제 #10
0
    def create_from_user(self, initiator_call, exten, flow, user_uuid):
        if not ari_helpers.channel_exists(self.ari, initiator_call):
            raise TransferCreationError('initiator channel not found')

        if Channel(initiator_call, self.ari).user() != user_uuid:
            raise TransferCreationError(
                'initiator call does not belong to authenticated user')

        try:
            transferred_call = Channel(initiator_call,
                                       self.ari).only_connected_channel()
        except TooManyChannels as e:
            raise TooManyTransferredCandidates(e.channels)
        except NotEnoughChannels as e:
            raise TransferCreationError('transferred channel not found')

        context = User(user_uuid, self.confd_client).main_line().context()

        return self.create(transferred_call,
                           initiator_call,
                           context,
                           exten,
                           flow,
                           variables={})
예제 #11
0
    def make_call_from_channel(self, ari, channel):
        channel_helper = Channel(channel.id, ari)
        call = Call(channel.id)
        call.creation_time = channel.json['creationtime']
        call.status = channel.json['state']
        call.caller_id_name = channel.json['caller']['name']
        call.caller_id_number = channel.json['caller']['number']
        call.peer_caller_id_name = channel.json['connected']['name']
        call.peer_caller_id_number = channel.json['connected']['number']
        call.user_uuid = channel_helper.user()
        call.on_hold = channel_helper.on_hold()
        call.bridges = [bridge.id for bridge in ari.bridges.list() if channel.id in bridge.json['channels']]
        call.talking_to = {connected_channel.id: connected_channel.user()
                           for connected_channel in channel_helper.connected_channels()}
        call.is_caller = channel_helper.is_caller()
        call.dialed_extension = channel_helper.dialed_extension()

        return call
예제 #12
0
    def create_from_user(self, initiator_call, destination, location,
                         completions, timeout, user_uuid):
        if Channel(initiator_call, self.ari).user() != user_uuid:
            raise UserPermissionDenied(user_uuid, {'call': initiator_call})

        if destination == 'line':
            try:
                destination_interface = User(
                    user_uuid,
                    self.confd_client).line(location['line_id']).interface()
            except (InvalidUserUUID, InvalidUserLine):
                raise RelocateCreationError('invalid line for user',
                                            details={
                                                'user_uuid': user_uuid,
                                                'line_id': location['line_id']
                                            })
            destination = 'interface'
            location['interface'] = destination_interface
            variables = {}
        elif destination == 'mobile':
            try:
                user = User(user_uuid, self.confd_client)
                mobile = user.mobile_phone_number()
                line_context = user.main_line().context()
            except (InvalidUserUUID, InvalidUserLine):
                details = {'user_uuid': user_uuid}
                raise RelocateCreationError(
                    'invalid user: could not find main line', details=details)
            destination = 'extension'
            location = {'exten': mobile, 'context': line_context}
            variables = {'WAZO_DEREFERENCED_USERUUID': user_uuid}

        relocate = Relocate(self.state_factory)
        relocate.initiator = user_uuid
        relocate.recipient_variables = variables

        return self.create(initiator_call,
                           destination,
                           location,
                           completions,
                           timeout,
                           relocate=relocate)
예제 #13
0
 def recipient_answered(self, relocate):
     relocate.events.publish('answered', relocate)
     if 'answer' in relocate.completions:
         completer = RelocateCompleter(self._amid, self._ari)
         if Channel(relocate.relocated_channel, self._ari).is_in_stasis():
             completer.bridge(relocate)
             try:
                 self._ari.channels.hangup(
                     channelId=relocate.initiator_channel)
             except ARINotFound:
                 pass
             except ARIException as e:
                 logger.exception('ARI error: %s', e)
             relocate.set_state('ended')
         else:
             completer.move_to_stasis(relocate)
             relocate.set_state('waiting_for_relocated')
     elif 'api' in relocate.completions:
         relocate.set_state('waiting_for_completion')
     else:
         raise NotImplementedError()
예제 #14
0
    def create(self, transferred_channel, initiator_channel, context, exten, variables):
        initiator_uuid = Channel(initiator_channel.id, self._ari).user()
        if initiator_uuid is None:
            raise TransferCreationError('initiator has no user UUID')

        transfer_bridge = self._ari.bridges.create(type='mixing', name='transfer')
        transfer_id = transfer_bridge.id
        try:
            transferred_channel.setChannelVar(variable='XIVO_TRANSFER_ROLE', value='transferred')
            transferred_channel.setChannelVar(variable='XIVO_TRANSFER_ID', value=transfer_id)
            initiator_channel.setChannelVar(variable='XIVO_TRANSFER_ROLE', value='initiator')
            initiator_channel.setChannelVar(variable='XIVO_TRANSFER_ID', value=transfer_id)
            transfer_bridge.addChannel(channel=transferred_channel.id)
            transfer_bridge.addChannel(channel=initiator_channel.id)
        except ARINotFound:
            raise TransferCreationError('some channel got hung up')

        try:
            ari_helpers.hold_transferred_call(self._ari, transferred_channel.id)
        except ARINotFound:
            raise TransferCreationError('transferred call hung up')

        try:
            self._ari.channels.ring(channelId=initiator_channel.id)
        except ARINotFound:
            raise TransferCreationError('initiator call hung up')

        recipient_call = self._services.originate_recipient(initiator_channel.id, context, exten, transfer_id, variables)

        self.transfer = Transfer(transfer_id, initiator_uuid)
        self.transfer.transferred_call = transferred_channel.id
        self.transfer.initiator_call = initiator_channel.id
        self.transfer.recipient_call = recipient_call
        self.transfer.status = self.name
        self._notifier.created(self.transfer)

        return TransferStateRingback.from_state(self)
예제 #15
0
 def list_calls_user(self, user_uuid, application_filter=None, application_instance_filter=None):
     calls = self.list_calls(application_filter, application_instance_filter)
     return [call for call in calls if call.user_uuid == user_uuid and not Channel(call.id_, self._ari).is_local()]