def parse_grammar(self, element, uri=None): Grammar.parse_grammar(self, element, uri) # Extract Loop attribute loop = int(self.extract_attribute_value("loop")) if loop < 0: raise RESTFormatException("Play loop must be a positive integer") self.loop_times = loop # Pull out the text within the element audio_path = element.text.strip() if audio_path is None: raise RESTFormatException("No File for play given!") if not is_valid_url(audio_path): if file_exists(audio_path): self.sound_file_path = audio_path else: if url_exists(audio_path): if audio_path[-4:].lower() != '.mp3': error_msg = "Only mp3 files allowed for remote file play" print error_msg if audio_path[:7].lower() == "http://": audio_path = audio_path[7:] elif audio_path[:8].lower() == "https://": audio_path = audio_path[8:] elif audio_path[:6].lower() == "ftp://": audio_path = audio_path[6:] else: pass self.sound_file_path = "shout://%s" % audio_path
def parse_grammar(self, element, uri=None): Grammar.parse_grammar(self, element, uri) max_length = self.extract_attribute_value("maxLength") timeout = self.extract_attribute_value("timeout") action = self.extract_attribute_value("action") finish_on_key = self.extract_attribute_value("finishOnKey") self.file_path = self.extract_attribute_value("filePath") if self.file_path: self.file_path = os.path.normpath(self.file_path) + os.sep self.play_beep = self.extract_attribute_value("playBeep") self.format = self.extract_attribute_value("format") self.prefix = self.extract_attribute_value("prefix") method = self.extract_attribute_value("method") if method != 'GET' and method != 'POST': raise RESTAttributeException("Method must be 'GET' or 'POST'") self.method = method if max_length < 0: raise RESTFormatException("Record 'maxLength' must be a positive integer") self.max_length = max_length if timeout < 0: raise RESTFormatException("Record 'timeout' must be positive") self.timeout = timeout if action and is_valid_url(action): self.action = action else: self.action = uri # :TODO Validate Finish on Key self.finish_on_key = finish_on_key
def parse_element(self, element, uri=None): Element.parse_element(self, element, uri) # Extract Loop attribute try: loop = int(self.extract_attribute_value("loop", 1)) except ValueError: loop = 1 if loop < 0: raise RESTFormatException("Play 'loop' must be a positive integer or 0") self.loop_times = loop # Pull out the text within the element audio_path = element.text.strip() if not audio_path: raise RESTFormatException("No File to play set !") if not is_valid_url(audio_path): if file_exists(audio_path): self.sound_file_path = audio_path else: if url_exists(audio_path): if audio_path[-4:].lower() != '.mp3': raise RESTFormatException("Only mp3 files allowed for remote file play") if audio_path[:7].lower() == "http://": audio_path = audio_path[7:] elif audio_path[:8].lower() == "https://": audio_path = audio_path[8:] elif audio_path[:6].lower() == "ftp://": audio_path = audio_path[6:] else: pass self.sound_file_path = "shout://%s" % audio_path
def parse_grammar(self, element, uri=None): Grammar.parse_grammar(self, element, uri) method = self.extract_attribute_value("method") if not method in ('GET', 'POST'): raise RESTAttributeException("Method must be 'GET' or 'POST'") self.method = method url = element.text.strip() if not url: raise RESTFormatException("Redirect must have a URL") if not is_valid_url(url): raise RESTFormatException("Redirect URL not valid!") self.url = url
def parse_grammar(self, element, uri=None): Grammar.parse_grammar(self, element, uri) num_digits = int(self.extract_attribute_value("numDigits")) if num_digits > self.DEFAULT_MAX_DIGITS: num_digits = self.DEFAULT_MAX_DIGITS if num_digits < 1: raise RESTFormatException("GetDigits 'numDigits' must be greater than 0") try: timeout = int(self.extract_attribute_value("timeout")) except ValueError: timeout = self.DEFAULT_TIMEOUT * 1000 if timeout < 0: raise RESTFormatException("GetDigits 'timeout' must be a positive integer") finish_on_key = self.extract_attribute_value("finishOnKey") play_beep = self.extract_attribute_value("playBeep") self.invalid_digits_sound = \ self.extract_attribute_value("invalidDigitsSound") self.valid_digits = self.extract_attribute_value("validDigits") action = self.extract_attribute_value("action") try: retries = int(self.extract_attribute_value("retries")) except ValueError: retries = 1 if retries < 0: raise RESTFormatException("GetDigits 'retries' must be greater than 0") method = self.extract_attribute_value("method") if method != 'GET' and method != 'POST': raise RESTAttributeException("Method, must be 'GET' or 'POST'") self.method = method if play_beep == 'true': self.play_beep = True else: self.play_beep = False if action and is_valid_url(action): self.action = action else: self.action = uri self.num_digits = num_digits self.timeout = timeout * 1000 self.finish_on_key = finish_on_key self.retries = retries
def transfer_call(self): """Transfer Call Realtime call transfer allows you to interrupt an in-progress call and place it another scenario. To transfer a live call, you make an HTTP POST request to a resource URI. POST Parameters --------------- The following parameters are available for you to POST when transfering a phone call: CallUUID: Unique Call ID to which the action should occur to. URL: A valid URL that returns RESTXML. Plivo will immediately fetch the XML and continue the call as the new XML. """ msg = "" result = False call_uuid = get_post_param(request, 'CallUUID') new_xml_url = get_post_param(request, 'Url') if not call_uuid: msg = "CallUUID Parameter must be present" return flask.jsonify(Success=result, Message=msg) elif not new_xml_url: msg = "URL Parameter must be present" return flask.jsonify(Success=result, Message=msg) elif not is_valid_url(new_xml_url): msg = "URL is not Valid" return flask.jsonify(Success=result, Message=msg) msg = "Call UUID must be present with URL" res = self._rest_inbound_socket.transfer_call(new_xml_url, call_uuid) if res: msg = "Transfer Call Executed" result = True else: msg = "Transfer Call Failed" return flask.jsonify(Success=result, Message=msg)
def _prepare_moh(self): mohs = [] if not self.dial_music: return mohs for audio_path in self.dial_music.split(','): if not is_valid_url(audio_path): if file_exists(audio_path): mohs.append(audio_path) else: if url_exists(audio_path): if audio_path[-4:].lower() != '.mp3': raise RESTFormatException("Only mp3 files allowed for remote file play") if audio_path[:7].lower() == "http://": audio_path = audio_path[7:] elif audio_path[:8].lower() == "https://": audio_path = audio_path[8:] elif audio_path[:6].lower() == "ftp://": audio_path = audio_path[6:] else: pass mohs.append("shout://%s" % audio_path) return mohs
def bulk_call(self): """Make Bulk Outbound Calls in one request Allow initiating bulk outbound calls via the REST API. To make a bulk outbound call, make an HTTP POST request to the resource URI. POST Parameters ---------------- Required Parameters - You must POST the following parameters: From: The phone number to use as the caller id for the call without the leading + To: The number to call without the leading + Gateways: Comma separated string of gateways to dial the call out GatewayCodecs: Comma separated string of codecs for gateways GatewayTimeouts: Comma separated string of timeouts for gateways GatewayRetries: Comma separated string of retries for gateways AnswerUrl: The URL that should be requested for XML when the call connects. Similar to the URL for your inbound calls TimeLimit: Define the max time of the calls Optional Parameters - You may POST the following parameters: [HangUpUrl]: URL that Plivo will notify to, with POST params when calls ends [RingUrl]: URL that Plivo will notify to, with POST params when calls starts ringing [HangupOnRing]: If Set to 0 we will hangup as soon as the number ring, if set to value X we will wait X seconds when start ringing and then hang up [OriginateDialString]: Additional Originate dialstring to be executed while making the outbound call [SendDigits]: A string of keys to dial after connecting to the number. Valid digits in the string include: any digit (0-9), '#' and '*'. Very useful, if you want to connect to a company phone number, and wanted to dial extension 1234 and then the pound key, use SendDigits=1234#. Remember to URL-encode this string, since the '#' character has special meaning in a URL. To wait before sending DTMF to the extension, you can add leading 'w' characters. Each 'w' character waits 0.5 seconds instead of sending a digit. """ msg = "" result = False request_uuid = "" request_uuid_list = [] i = 0 caller_id = get_post_param(request, 'From') to_str = get_post_param(request, 'To') gw_str = get_post_param(request, 'Gateways') answer_url = get_post_param(request, 'AnswerUrl') delimiter = get_post_param(request, 'Delimiter') if delimiter in (',', '/'): msg = "This Delimiter not allowed" elif not caller_id or not to_str or not gw_str or not answer_url or\ not delimiter: msg = "Mandatory Parameters Missing" elif not is_valid_url(answer_url): msg = "Answer URL is not Valid" else: hangup_url = get_post_param(request, 'HangupUrl') ring_url = get_post_param(request, 'RingUrl') if hangup_url and not is_valid_url(hangup_url): msg = "Hangup URL is not Valid" elif ring_url and not is_valid_url(ring_url): msg = "Ring URL is not Valid" else: extra_dial_string = get_post_param(request, 'ExtraDialString') # Is a string of strings gw_codecs_str = get_post_param(request, 'GatewayCodecs') gw_timeouts_str = get_post_param(request, 'GatewayTimeouts') gw_retries_str = get_post_param(request, 'GatewayRetries') send_digits_str = get_post_param(request, 'SendDigits') time_limit_str = get_post_param(request, 'TimeLimit') hangup_on_ring_str = get_post_param(request, 'HangupOnRing') to_str_list = to_str.split(delimiter) gw_str_list = gw_str.split(delimiter) gw_codecs_str_list = gw_codecs_str.split(delimiter) gw_timeouts_str_list = gw_timeouts_str.split(delimiter) gw_retries_str_list = gw_retries_str.split(delimiter) send_digits_list = send_digits_str.split(delimiter) time_limit_list = time_limit_str.split(delimiter) hangup_on_ring_list = hangup_on_ring_str.split(delimiter) if len(to_str_list) < 2: msg = "BulkCalls should be used for at least 2 numbers" elif len(to_str_list) != len(gw_str_list): msg = "'To' parameter length does not match 'GW' Length" else: for to in to_str_list: try: gw_codecs = gw_codecs_str_list[i] except IndexError: gw_codecs = "" try: gw_timeouts = gw_timeouts_str_list[i] except IndexError: gw_timeouts = "" try: gw_retries = gw_retries_str_list[i] except IndexError: gw_retries = "" try: send_digits = send_digits_list[i] except IndexError: send_digits = "" try: time_limit = time_limit_list[i] except IndexError: time_limit = "" try: hangup_on_ring = hangup_on_ring_list[i] except IndexError: hangup_on_ring = "" call_req = self._prepare_call_request( caller_id, to, extra_dial_string, gw_str_list[i], gw_codecs, gw_timeouts, gw_retries, send_digits, time_limit, hangup_on_ring, answer_url, ring_url, hangup_url) request_uuid = call_req.request_uuid request_uuid_list.append(request_uuid) self._rest_inbound_socket.call_requests[request_uuid] = call_req i += 1 # now do the calls ! if self._rest_inbound_socket.bulk_originate(request_uuid_list): msg = "BulkCalls Requests Executed" result = True else: msg = "BulkCalls Requests Failed" request_uuid_list = [] return flask.jsonify(Success=result, Message=msg, RequestUUID=request_uuid_list)
def call(self): """Make Outbound Call Allow initiating outbound calls via the REST API. To make an outbound call, make an HTTP POST request to the resource URI. POST Parameters ---------------- Required Parameters - You must POST the following parameters: From: The phone number to use as the caller id for the call without the leading + To: The number to call without the leading + Gateways: Comma separated string of gateways to dial the call out GatewayCodecs: Comma separated string of codecs for gateways GatewayTimeouts: Comma separated string of timeouts for gateways GatewayRetries: Comma separated string of retries for gateways AnswerUrl: The URL that should be requested for XML when the call connects TimeLimit: Define the max time of the call Optional Parameters - You may POST the following parameters: [HangUpUrl]: URL that Plivo will notify to, with POST params when calls ends [RingUrl]: URL that Plivo will notify to, with POST params when calls starts ringing [HangupOnRing]: If Set to 0 we will hangup as soon as the number ring, if set to value X we will wait X seconds when start ringing and then hang up [OriginateDialString]: Additional Originate dialstring to be executed while making the outbound call [SendDigits]: A string of keys to dial after connecting to the number. Valid digits in the string include: any digit (0-9), '#' and '*'. Very useful, if you want to connect to a company phone number, and wanted to dial extension 1234 and then the pound key, use SendDigits=1234#. Remember to URL-encode this string, since the '#' character has special meaning in a URL. To wait before sending DTMF to the extension, you can add leading 'w' or 'W' characters. Each 'w' character waits 0.5 seconds and each 'W' character waits for 1.0 seconds instead of sending a digit. """ msg = "" result = False request_uuid = "" caller_id = get_post_param(request, 'From') to = get_post_param(request, 'To') gw = get_post_param(request, 'Gateways') answer_url = get_post_param(request, 'AnswerUrl') if not caller_id or not to or not gw or not answer_url: msg = "Mandatory Parameters Missing" elif not is_valid_url(answer_url): msg = "Answer URL is not Valid" else: hangup_url = get_post_param(request, 'HangupUrl') ring_url = get_post_param(request, 'RingUrl') if hangup_url and not is_valid_url(hangup_url): msg = "Hangup URL is not Valid" elif ring_url and not is_valid_url(ring_url): msg = "Ring URL is not Valid" else: extra_dial_string = get_post_param(request, 'ExtraDialString') gw_codecs = get_post_param(request, 'GatewayCodecs') gw_timeouts = get_post_param(request, 'GatewayTimeouts') gw_retries = get_post_param(request, 'GatewayRetries') send_digits = get_post_param(request, 'SendDigits') time_limit = get_post_param(request, 'TimeLimit') hangup_on_ring = get_post_param(request, 'HangupOnRing') call_req = self._prepare_call_request( caller_id, to, extra_dial_string, gw, gw_codecs, gw_timeouts, gw_retries, send_digits, time_limit, hangup_on_ring, answer_url, ring_url, hangup_url) request_uuid = call_req.request_uuid self._rest_inbound_socket.call_requests[request_uuid] = call_req self._rest_inbound_socket.spawn_originate(request_uuid) msg = "Call Request Executed" result = True return flask.jsonify(Success=result, Message=msg, RequestUUID=request_uuid)
def play_on_call(self, call_uuid="", sounds_list=[], legs="aleg", length=3600, schedule=0, mix=True, loop=False): cmds = [] error_count = 0 bleg = None # set flags if loop: aflags = "l" bflags = "l" else: aflags = "" bflags = "" if mix: aflags += "m" bflags += "mr" else: bflags += "r" if schedule <= 0: name = "Call Play" else: name = "Call SchedulePlay" if not call_uuid: self.log.error("%s Failed -- Missing CallUUID" % name) return False if not sounds_list: self.log.error("%s Failed -- Missing Sounds" % name) return False if not legs in ('aleg', 'bleg', 'both'): self.log.error("%s Failed -- Invalid legs arg '%s'" % (name, str(legs))) return False # get sound files sounds_to_play = [] for sound in sounds_list: if is_valid_sound_proto(sound): sounds_to_play.append(sound) elif not is_valid_url(sound): if file_exists(sound): sounds_to_play.append(sound) else: self.log.warn("%s -- File %s not found" % (name, sound)) else: url = normalize_url_space(sound) sound_file_path = get_resource(self, url) if sound_file_path: sounds_to_play.append(sound_file_path) else: self.log.warn("%s -- Url %s not found" % (name, url)) if not sounds_to_play: self.log.error("%s Failed -- Sound files not found" % name) return False # build command play_str = '!'.join(sounds_to_play) play_aleg = 'file_string://%s' % play_str play_bleg = 'file_string://silence_stream://1!%s' % play_str # aleg case if legs == 'aleg': # add displace command for displace in self._get_displace_media_list(call_uuid): cmd = "uuid_displace %s stop %s" % (call_uuid, displace) cmds.append(cmd) cmd = "uuid_displace %s start %s %d %s" % (call_uuid, play_aleg, length, aflags) cmds.append(cmd) # bleg case elif legs == 'bleg': # get bleg bleg = self.get_var("bridge_uuid", uuid=call_uuid) # add displace command if bleg: for displace in self._get_displace_media_list(call_uuid): cmd = "uuid_displace %s stop %s" % (call_uuid, displace) cmds.append(cmd) cmd = "uuid_displace %s start %s %d %s" % (call_uuid, play_bleg, length, bflags) cmds.append(cmd) else: self.log.error("%s Failed -- No BLeg found" % name) return False # both legs case elif legs == 'both': # get bleg bleg = self.get_var("bridge_uuid", uuid=call_uuid) # add displace commands for displace in self._get_displace_media_list(call_uuid): cmd = "uuid_displace %s stop %s" % (call_uuid, displace) cmds.append(cmd) cmd = "uuid_displace %s start %s %d %s" % (call_uuid, play_aleg, length, aflags) cmds.append(cmd) # get the bleg if bleg: cmd = "uuid_displace %s start %s %d %s" % (call_uuid, play_bleg, length, bflags) cmds.append(cmd) else: self.log.warn("%s -- No BLeg found" % name) else: self.log.error("%s Failed -- Invalid Legs '%s'" % (name, legs)) return False # case no schedule if schedule <= 0: for cmd in cmds: res = self.api(cmd) if not res.is_success(): self.log.error("%s Failed '%s' -- %s" % (name, cmd, res.get_response())) error_count += 1 if error_count > 0: return False return True # case schedule sched_id = str(uuid.uuid1()) for cmd in cmds: sched_cmd = "sched_api +%d %s %s" % (schedule, sched_id, cmd) res = self.api(sched_cmd) if res.is_success(): self.log.info("%s '%s' with SchedPlayId %s" % (name, sched_cmd, sched_id)) else: self.log.error("%s Failed '%s' -- %s" % (name, sched_cmd, res.get_response())) error_count += 1 if error_count > 0: return False return sched_id
def run(self, outbound_socket): outbound_socket.log.info("Dial Started") dial_options = [] numbers = [] # Set timeout outbound_socket.set("call_timeout=%d" % self.timeout) outbound_socket.set("answer_timeout=%d" % self.timeout) # Set callerid if self.caller_id: caller_id = "effective_caller_id_number=%s" % self.caller_id dial_options.append(caller_id) # Set numbers to dial from Number nouns for child in self.children: if isinstance(child, Number): dial_num = self.create_number(child) if not dial_num: continue numbers.append(dial_num) # Create dialstring self.dial_str = '{' self.dial_str += ','.join(dial_options) self.dial_str += '}' self.dial_str += ','.join(numbers) # Don't hangup after bridge ! outbound_socket.set("hangup_after_bridge=false") # Set time limit: when reached, B Leg is hung up sched_hangup_id = str(uuid.uuid1()) hangup_str = "api_on_answer=sched_api +%d %s uuid_transfer %s -bleg 'hangup:ALLOTTED_TIMEOUT' inline" \ % (self.time_limit, sched_hangup_id, outbound_socket.get_channel_unique_id()) outbound_socket.set(hangup_str) # Set hangup on '*' if self.hangup_on_star: outbound_socket.set("bridge_terminate_key=*") # Play Dial music or bridge the early media accordingly if self.dial_music: outbound_socket.set("bridge_early_media=true") outbound_socket.set("instant_ringback=true") outbound_socket.set("ringback=file_string://%s" % self.dial_music) else: outbound_socket.set("bridge_early_media=true") if self.confirm_sound: # Use confirm key if present else just play music if self.confirm_key: confirm_music_str = "group_confirm_file=%s" % self.confirm_sound confirm_key_str = "group_confirm_key=%s" % self.confirm_key else: confirm_music_str = "group_confirm_file=playback %s" % self.confirm_sound confirm_key_str = "group_confirm_key=exec" # Cancel the leg timeout after the call is answered outbound_socket.set("group_confirm_cancel_timeout=1") outbound_socket.set(confirm_music_str) outbound_socket.set(confirm_key_str) # Start dial outbound_socket.bridge(self.dial_str) event = outbound_socket._action_queue.get() reason = None originate_disposition = event['variable_originate_disposition'] hangup_cause = originate_disposition if hangup_cause == 'ORIGINATOR_CANCEL': reason = '%s (A leg)' % hangup_cause else: reason = '%s (B leg)' % hangup_cause if not hangup_cause or hangup_cause == 'SUCCESS': hangup_cause = outbound_socket.get_hangup_cause() reason = '%s (A leg)' % hangup_cause if not hangup_cause: hangup_cause = outbound_socket.get_var('bridge_hangup_cause') reason = '%s (B leg)' % hangup_cause if not hangup_cause: hangup_cause = outbound_socket.get_var('hangup_cause') reason = '%s (A leg)' % hangup_cause outbound_socket.log.info("Dial Finished with reason: %s" \ % reason) # Unsched hangup outbound_socket.bgapi("sched_del %s" % sched_hangup_id) # Call url action if self.action and is_valid_url(self.action): self.fetch_rest_xml(self.action, method=self.method)
def execute(self, outbound_socket): dial_options = [] numbers = [] # Set timeout outbound_socket.set("call_timeout=%d" % self.timeout) outbound_socket.set("answer_timeout=%d" % self.timeout) # Set callerid or unset if not provided if self.caller_id: caller_id = "effective_caller_id_number=%s" % self.caller_id dial_options.append(caller_id) else: outbound_socket.unset("effective_caller_id_number") # Set ring flag if dial will ring. # But first set plivo_dial_rang to false # to be sure we don't get it from an old Dial outbound_socket.set("plivo_dial_rang=false") outbound_socket.set("execute_on_ring=eval ${uuid_setvar(%s plivo_dial_rang true}" \ % outbound_socket.get_channel_unique_id()) # Set numbers to dial from Number nouns for child in self.children: if isinstance(child, Number): dial_num = self.create_number(child, outbound_socket) if not dial_num: continue numbers.append(dial_num) if not numbers: outbound_socket.log.error("Dial Aborted, No Number to dial !") return # Create dialstring self.dial_str = '{' self.dial_str += ','.join(dial_options) self.dial_str += '}' self.dial_str += ','.join(numbers) # Don't hangup after bridge ! outbound_socket.set("hangup_after_bridge=false") # Set time limit: when reached, B Leg is hung up sched_hangup_id = str(uuid.uuid1()) hangup_str = "api_on_answer=sched_api +%d %s uuid_transfer %s -bleg 'hangup:ALLOTTED_TIMEOUT' inline" \ % (self.time_limit, sched_hangup_id, outbound_socket.get_channel_unique_id()) outbound_socket.set(hangup_str) # Set hangup on '*' or unset if not provided if self.hangup_on_star: outbound_socket.set("bridge_terminate_key=*") else: outbound_socket.unset("bridge_terminate_key") # Play Dial music or bridge the early media accordingly mohs = self._prepare_moh() if not mohs: outbound_socket.set("bridge_early_media=true") outbound_socket.unset("instant_ringback") outbound_socket.unset("ringback") else: outbound_socket.set("playback_delimiter=!") play_str = "file_string://silence_stream://1" for moh in mohs: play_str = "%s!%s" % (play_str, moh) outbound_socket.set("bridge_early_media=true") outbound_socket.set("instant_ringback=true") outbound_socket.set("ringback=%s" % play_str) # Set confirm sound and key or unset if not provided if self.confirm_sound: # Use confirm key if present else just play music if self.confirm_key: confirm_music_str = "group_confirm_file=%s" % self.confirm_sound confirm_key_str = "group_confirm_key=%s" % self.confirm_key else: confirm_music_str = "group_confirm_file=playback %s" % self.confirm_sound confirm_key_str = "group_confirm_key=exec" # Cancel the leg timeout after the call is answered outbound_socket.set("group_confirm_cancel_timeout=1") outbound_socket.set(confirm_music_str) outbound_socket.set(confirm_key_str) else: outbound_socket.unset("group_confirm_cancel_timeout") outbound_socket.unset("group_confirm_file") outbound_socket.unset("group_confirm_key") # Start dial outbound_socket.log.info("Dial Started %s" % self.dial_str) outbound_socket.bridge(self.dial_str) event = outbound_socket.wait_for_action() reason = None originate_disposition = event['variable_originate_disposition'] hangup_cause = originate_disposition if hangup_cause == 'ORIGINATOR_CANCEL': reason = '%s (A leg)' % hangup_cause else: reason = '%s (B leg)' % hangup_cause if not hangup_cause or hangup_cause == 'SUCCESS': hangup_cause = outbound_socket.get_hangup_cause() reason = '%s (A leg)' % hangup_cause if not hangup_cause: hangup_cause = outbound_socket.get_var('bridge_hangup_cause') reason = '%s (B leg)' % hangup_cause if not hangup_cause: hangup_cause = outbound_socket.get_var('hangup_cause') reason = '%s (A leg)' % hangup_cause outbound_socket.log.info("Dial Finished with reason: %s" \ % reason) # Unschedule hangup task outbound_socket.bgapi("sched_del %s" % sched_hangup_id) # Get ring status dial_rang = outbound_socket.get_var("plivo_dial_rang") == 'true' # If action is set, redirect to this url # Otherwise, continue to next Element if self.action and is_valid_url(self.action): params = {} if dial_rang: params['RingStatus'] = 'true' else: params['RingStatus'] = 'false' params['HangupCause'] = hangup_cause self.fetch_rest_xml(self.action, params, method=self.method)