PRI signaling module. More...
#include "asterisk.h"#include <errno.h>#include <ctype.h>#include <signal.h>#include "asterisk/utils.h"#include "asterisk/options.h"#include "asterisk/pbx.h"#include "asterisk/app.h"#include "asterisk/file.h"#include "asterisk/callerid.h"#include "asterisk/say.h"#include "asterisk/manager.h"#include "asterisk/astdb.h"#include "asterisk/causes.h"#include "asterisk/musiconhold.h"#include "asterisk/cli.h"#include "asterisk/transcap.h"#include "asterisk/features.h"#include "asterisk/aoc.h"#include "sig_pri.h"
Go to the source code of this file.
Data Structures | |
| struct | sig_pri_cc_agent_prv |
| struct | sig_pri_cc_monitor_instance |
| struct | xfer_rsp_data |
Defines | |
| #define | DCHAN_AVAILABLE (DCHAN_NOTINALARM | DCHAN_UP) |
| #define | DCHAN_NOTINALARM (1 << 0) |
| #define | DCHAN_UP (1 << 1) |
| #define | PRI_CHANNEL(p) ((p) & 0xff) |
| #define | PRI_CIS_CALL (1 << 17) |
| #define | PRI_DEADLOCK_AVOIDANCE(p) |
| #define | PRI_EXPLICIT (1 << 16) |
| #define | PRI_HELD_CALL (1 << 18) |
| #define | PRI_SPAN(p) (((p) >> 8) & 0xff) |
Typedefs | |
| typedef void(* | xfer_rsp_callback )(void *data, int is_successful) |
| Protocol callback to indicate if transfer will happen. | |
Enumerations | |
| enum | SIG_PRI_CALL_OPT_ARGS { OPT_ARG_KEYPAD = 0, OPT_ARG_AOC_REQUEST, OPT_ARG_ARRAY_SIZE } |
| enum | SIG_PRI_CALL_OPT_FLAGS { OPT_KEYPAD = (1 << 0), OPT_REVERSE_CHARGE = (1 << 1), OPT_AOC_REQUEST = (1 << 2) } |
Functions | |
| static void | apply_plan_to_number (char *buf, size_t size, const struct sig_pri_span *pri, const char *number, const int plan) |
| static unsigned char | ast_pri_pack_hex_char (char c) |
| static int | ast_pri_pack_hex_string (unsigned char *dst, char *src, int maxlen) |
| static int | ast_to_pri_char_set (enum AST_PARTY_CHAR_SET ast_char_set) |
| static int | ast_to_pri_presentation (int ast_presentation) |
| static int | ast_to_pri_reason (enum AST_REDIRECTING_REASON ast_reason) |
| static void | build_status (char *s, size_t len, int status, int active) |
| static int | detect_aoc_e_subcmd (const struct pri_subcommands *subcmds) |
| static char * | dialplan2str (int dialplan) |
| static void * | do_idle_thread (void *v_pvt) |
| static int | pri_active_dchan_index (struct sig_pri_span *pri) |
| static int | pri_check_restart (struct sig_pri_span *pri) |
| static void * | pri_dchannel (void *vpri) |
| void | pri_event_alarm (struct sig_pri_span *pri, int index, int before_start_pri) |
| void | pri_event_noalarm (struct sig_pri_span *pri, int index, int before_start_pri) |
| static int | pri_find_dchan (struct sig_pri_span *pri) |
| static int | pri_find_empty_chan (struct sig_pri_span *pri, int backwards) |
| static int | pri_find_empty_nobch (struct sig_pri_span *pri) |
| static int | pri_find_pri_call (struct sig_pri_span *pri, q931_call *call) |
| static int | pri_find_principle (struct sig_pri_span *pri, int channel, q931_call *call) |
| static int | pri_fixup_principle (struct sig_pri_span *pri, int principle, q931_call *call) |
| static int | pri_grab (struct sig_pri_chan *p, struct sig_pri_span *pri) |
| int | pri_is_up (struct sig_pri_span *pri) |
| int | pri_maintenance_bservice (struct pri *pri, struct sig_pri_chan *p, int changestatus) |
| static char * | pri_order (int level) |
| static void | pri_queue_control (struct sig_pri_span *pri, int chanpos, int subclass) |
| static void | pri_queue_frame (struct sig_pri_span *pri, int chanpos, struct ast_frame *frame) |
| static void | pri_rel (struct sig_pri_span *pri) |
| int | pri_send_callrerouting_facility_exec (struct sig_pri_chan *p, enum ast_channel_state chanstate, const char *destination, const char *original, const char *reason) |
| int | pri_send_keypad_facility_exec (struct sig_pri_chan *p, const char *digits) |
| static void * | pri_ss_thread (void *data) |
| static enum AST_PARTY_CHAR_SET | pri_to_ast_char_set (int pri_char_set) |
| static int | pri_to_ast_presentation (int pri_presentation) |
| static enum AST_REDIRECTING_REASON | pri_to_ast_reason (int pri_reason) |
| static unsigned int | PVT_TO_CHANNEL (struct sig_pri_chan *p) |
| static char * | redirectingreason2str (int redirectingreason) |
| int | sig_pri_answer (struct sig_pri_chan *p, struct ast_channel *ast) |
| static enum ast_aoc_s_charged_item | sig_pri_aoc_charged_item_to_ast (enum PRI_AOC_CHARGED_ITEM value) |
| static enum PRI_AOC_CHARGED_ITEM | sig_pri_aoc_charged_item_to_pri (enum PRI_AOC_CHARGED_ITEM value) |
| static void | sig_pri_aoc_d_from_ast (struct sig_pri_chan *pvt, struct ast_aoc_decoded *decoded) |
| static void | sig_pri_aoc_d_from_pri (const struct pri_subcmd_aoc_d *aoc_d, struct ast_channel *owner, int passthrough) |
| static void | sig_pri_aoc_e_from_ast (struct sig_pri_chan *pvt, struct ast_aoc_decoded *decoded) |
| static void | sig_pri_aoc_e_from_pri (const struct pri_subcmd_aoc_e *aoc_e, struct ast_channel *owner, int passthrough) |
| static int | sig_pri_aoc_multiplier_from_ast (enum ast_aoc_currency_multiplier mult) |
| static int | sig_pri_aoc_multiplier_from_pri (const int mult) |
| static void | sig_pri_aoc_request_from_pri (const struct pri_subcmd_aoc_request *aoc_request, struct sig_pri_chan *pvt, q931_call *call) |
| static void | sig_pri_aoc_s_from_ast (struct sig_pri_chan *pvt, struct ast_aoc_decoded *decoded) |
| static void | sig_pri_aoc_s_from_pri (const struct pri_subcmd_aoc_s *aoc_s, struct ast_channel *owner, int passthrough) |
| static enum ast_aoc_time_scale | sig_pri_aoc_scale_to_ast (enum PRI_AOC_TIME_SCALE value) |
| static enum PRI_AOC_TIME_SCALE | sig_pri_aoc_scale_to_pri (enum ast_aoc_time_scale value) |
| static int | sig_pri_attempt_transfer (struct sig_pri_span *pri, q931_call *call_1_pri, int call_1_held, q931_call *call_2_pri, int call_2_held, xfer_rsp_callback rsp_callback, void *data) |
| int | sig_pri_available (struct sig_pri_chan **pvt, int is_specific_channel) |
| static int | sig_pri_available_check (struct sig_pri_chan *pvt) |
| int | sig_pri_call (struct sig_pri_chan *p, struct ast_channel *ast, char *rdest, int timeout, int layer1) |
| int | sig_pri_cc_agent_callee_available (struct ast_cc_agent *agent) |
| Alert the caller that it is time to try recalling. | |
| static int | sig_pri_cc_agent_cmp_cc_id (void *obj, void *arg, int flags) |
| void | sig_pri_cc_agent_destructor (struct ast_cc_agent *agent) |
| Destroy private data on the agent. | |
| int | sig_pri_cc_agent_init (struct ast_cc_agent *agent, struct sig_pri_chan *pvt_chan) |
| PRI CC agent initialization. | |
| int | sig_pri_cc_agent_party_b_free (struct ast_cc_agent *agent) |
| Let the caller know that the callee has become free but that the caller cannot attempt to call back because he is either busy or there is congestion on his line. | |
| void | sig_pri_cc_agent_req_ack (struct ast_cc_agent *agent) |
| Acknowledge CC request. | |
| int | sig_pri_cc_agent_start_monitoring (struct ast_cc_agent *agent) |
| Begin monitoring a busy device. | |
| int | sig_pri_cc_agent_start_offer_timer (struct ast_cc_agent *agent) |
| Start the offer timer. | |
| int | sig_pri_cc_agent_status_req (struct ast_cc_agent *agent) |
| Request the status of the agent's device. | |
| int | sig_pri_cc_agent_stop_offer_timer (struct ast_cc_agent *agent) |
| Stop the offer timer. | |
| int | sig_pri_cc_agent_stop_ringing (struct ast_cc_agent *agent) |
| Request for an agent's phone to stop ringing. | |
| static int | sig_pri_cc_available (struct sig_pri_span *pri, int chanpos, long cc_id, enum ast_cc_service_type service) |
| static void | sig_pri_cc_generic_check (struct sig_pri_span *pri, int chanpos, enum ast_cc_service_type service) |
| static void | sig_pri_cc_link_canceled (struct sig_pri_span *pri, long cc_id, int is_agent) |
| int | sig_pri_cc_monitor_cancel_available_timer (struct ast_cc_monitor *monitor, int *sched_id) |
| Cancel the running available timer. | |
| static int | sig_pri_cc_monitor_cmp_cc_id (void *obj, void *arg, int flags) |
| void | sig_pri_cc_monitor_destructor (void *monitor_pvt) |
| Destroy PRI private data on the monitor. | |
| static int | sig_pri_cc_monitor_instance_cmp_fn (void *obj, void *arg, int flags) |
| static void | sig_pri_cc_monitor_instance_destroy (void *data) |
| static int | sig_pri_cc_monitor_instance_hash_fn (const void *obj, const int flags) |
| static struct sig_pri_cc_monitor_instance * | sig_pri_cc_monitor_instance_init (int core_id, struct sig_pri_span *pri, long cc_id, const char *device_name) |
| int | sig_pri_cc_monitor_req_cc (struct ast_cc_monitor *monitor, int *available_timer_id) |
| Request CCSS. | |
| int | sig_pri_cc_monitor_status_rsp (struct ast_cc_monitor *monitor, enum ast_device_state devstate) |
| Status response to an ast_cc_monitor_status_request(). | |
| int | sig_pri_cc_monitor_suspend (struct ast_cc_monitor *monitor) |
| Suspend monitoring. | |
| int | sig_pri_cc_monitor_unsuspend (struct ast_cc_monitor *monitor) |
| Unsuspend monitoring. | |
| void | sig_pri_chan_alarm_notify (struct sig_pri_chan *p, int noalarm) |
| void | sig_pri_chan_delete (struct sig_pri_chan *doomed) |
| Delete the sig_pri private channel structure. | |
| struct sig_pri_chan * | sig_pri_chan_new (void *pvt_data, struct sig_pri_callback *callback, struct sig_pri_span *pri, int logicalspan, int channo, int trunkgroup) |
| void | sig_pri_cli_show_span (int fd, int *dchannels, struct sig_pri_span *pri) |
| void | sig_pri_cli_show_spans (int fd, int span, struct sig_pri_span *pri) |
| static int | sig_pri_cmp_pri_chans (const void *left, const void *right) |
| static struct sig_pri_chan * | sig_pri_cw_available (struct sig_pri_span *pri) |
| int | sig_pri_digit_begin (struct sig_pri_chan *pvt, struct ast_channel *ast, char digit) |
| static void | sig_pri_dsp_reset_and_flush_digits (struct sig_pri_chan *p) |
| static void | sig_pri_event_party_id (struct ast_str **msg, const char *prefix, struct ast_party_id *party) |
| void | sig_pri_extract_called_num_subaddr (struct sig_pri_chan *p, const char *rdest, char *called, size_t called_buff_size) |
| Extract the called number and subaddress from the dial string. | |
| static struct ast_cc_agent * | sig_pri_find_cc_agent_by_cc_id (struct sig_pri_span *pri, long cc_id) |
| static struct sig_pri_cc_monitor_instance * | sig_pri_find_cc_monitor_by_cc_id (struct sig_pri_span *pri, long cc_id) |
| void | sig_pri_fixup (struct ast_channel *oldchan, struct ast_channel *newchan, struct sig_pri_chan *pchan) |
| static void | sig_pri_fixup_chans (struct sig_pri_chan *old_chan, struct sig_pri_chan *new_chan) |
| static const char * | sig_pri_get_orig_dialstring (struct sig_pri_chan *p) |
| static void | sig_pri_handle_cis_subcmds (struct sig_pri_span *pri, int event_id, const struct pri_subcommands *subcmds, q931_call *call_rsp) |
| static void | sig_pri_handle_dchan_exception (struct sig_pri_span *pri, int index) |
| static int | sig_pri_handle_hold (struct sig_pri_span *pri, pri_event *ev) |
| static void | sig_pri_handle_retrieve (struct sig_pri_span *pri, pri_event *ev) |
| static void | sig_pri_handle_subcmds (struct sig_pri_span *pri, int chanpos, int event_id, int channel, const struct pri_subcommands *subcmds, q931_call *call_rsp) |
| int | sig_pri_hangup (struct sig_pri_chan *p, struct ast_channel *ast) |
| int | sig_pri_indicate (struct sig_pri_chan *p, struct ast_channel *chan, int condition, const void *data, size_t datalen) |
| static void | sig_pri_init_config (struct sig_pri_chan *pvt, struct sig_pri_span *pri) |
| void | sig_pri_init_pri (struct sig_pri_span *pri) |
| static int | sig_pri_is_cis_call (int channel) |
| int | sig_pri_load (const char *cc_type_name) |
| Load the sig_pri submodule. | |
| static void | sig_pri_lock_owner (struct sig_pri_span *pri, int chanpos) |
| static void | sig_pri_lock_private (struct sig_pri_chan *p) |
| static void | sig_pri_make_cc_dialstring (struct sig_pri_chan *p, char *buf, size_t buf_size) |
| static void | sig_pri_mcid_event (struct sig_pri_span *pri, const struct pri_subcmd_mcid_req *mcid, struct ast_channel *owner) |
| static int | sig_pri_msn_match (const char *msn_patterns, const char *exten) |
| static void | sig_pri_mwi_cache_update (struct sig_pri_span *pri) |
| static void | sig_pri_mwi_event_cb (const struct ast_event *event, void *userdata) |
| static struct ast_channel * | sig_pri_new_ast_channel (struct sig_pri_chan *p, int state, int ulaw, int transfercapability, char *exten, const struct ast_channel *requestor) |
| static void | sig_pri_open_media (struct sig_pri_chan *p) |
| static void | sig_pri_party_id_convert (struct ast_party_id *ast_id, const struct pri_party_id *pri_id, struct sig_pri_span *pri) |
| static void | sig_pri_party_id_from_ast (struct pri_party_id *pri_id, const struct ast_party_id *ast_id) |
| static void | sig_pri_party_name_convert (struct ast_party_name *ast_name, const struct pri_party_name *pri_name) |
| static void | sig_pri_party_name_from_ast (struct pri_party_name *pri_name, const struct ast_party_name *ast_name) |
| static void | sig_pri_party_number_convert (struct ast_party_number *ast_number, const struct pri_party_number *pri_number, struct sig_pri_span *pri) |
| static void | sig_pri_party_number_from_ast (struct pri_party_number *pri_number, const struct ast_party_number *ast_number) |
| static void | sig_pri_party_subaddress_from_ast (struct pri_party_subaddress *pri_subaddress, const struct ast_party_subaddress *ast_subaddress) |
| static int | sig_pri_play_tone (struct sig_pri_chan *p, enum sig_pri_tone tone) |
| static void | sig_pri_redirecting_convert (struct ast_party_redirecting *ast_redirecting, const struct pri_party_redirecting *pri_redirecting, const struct ast_party_redirecting *ast_guide, struct sig_pri_span *pri) |
| static void | sig_pri_redirecting_update (struct sig_pri_chan *pvt, struct ast_channel *ast) |
| struct ast_channel * | sig_pri_request (struct sig_pri_chan *p, enum sig_pri_law law, const struct ast_channel *requestor, int transfercapability) |
| static void | sig_pri_send_aoce_termination_request (struct sig_pri_span *pri, int chanpos, unsigned int ms) |
| static void | sig_pri_send_mwi_indication (struct sig_pri_span *pri, const char *mbox_number, const char *mbox_context, int num_messages) |
| static void | sig_pri_set_alarm (struct sig_pri_chan *p, int in_alarm) |
| static void | sig_pri_set_caller_id (struct sig_pri_chan *p) |
| static void | sig_pri_set_dialing (struct sig_pri_chan *p, int is_dialing) |
| static void | sig_pri_set_digital (struct sig_pri_chan *p, int is_digital) |
| static void | sig_pri_set_dnid (struct sig_pri_chan *p, const char *dnid) |
| static int | sig_pri_set_echocanceller (struct sig_pri_chan *p, int enable) |
| static void | sig_pri_set_rdnis (struct sig_pri_chan *p, const char *rdnis) |
| static void | sig_pri_set_subaddress (struct ast_party_subaddress *ast_subaddress, const struct pri_party_subaddress *pri_subaddress) |
| static void | sig_pri_sort_pri_chans (struct sig_pri_span *pri) |
| static void | sig_pri_span_devstate_changed (struct sig_pri_span *pri) |
| int | sig_pri_start_pri (struct sig_pri_span *pri) |
| void | sig_pri_stop_pri (struct sig_pri_span *pri) |
| Stop PRI span. | |
| static void | sig_pri_transfer_rsp (void *data, int is_successful) |
| void | sig_pri_unload (void) |
| Unload the sig_pri submodule. | |
| static void | sig_pri_unlock_private (struct sig_pri_chan *p) |
Variables | |
| static int | pri_gendigittimeout = 8000 |
| static int | pri_matchdigittimeout = 3000 |
| static struct ast_app_option | sig_pri_call_opts [128] = { [ 'K' ] = { .flag = OPT_KEYPAD , .arg_index = OPT_ARG_KEYPAD + 1 }, [ 'R' ] = { .flag = OPT_REVERSE_CHARGE }, [ 'A' ] = { .flag = OPT_AOC_REQUEST , .arg_index = OPT_ARG_AOC_REQUEST + 1 }, } |
| static struct ao2_container * | sig_pri_cc_monitors |
| static const char * | sig_pri_cc_type_name |
PRI signaling module.
Definition in file sig_pri.c.
| #define DCHAN_AVAILABLE (DCHAN_NOTINALARM | DCHAN_UP) |
Definition at line 101 of file sig_pri.c.
Referenced by pri_find_dchan(), and pri_is_up().
| #define DCHAN_NOTINALARM (1 << 0) |
Definition at line 90 of file sig_pri.c.
Referenced by build_status(), pri_event_alarm(), and pri_event_noalarm().
| #define DCHAN_UP (1 << 1) |
Definition at line 91 of file sig_pri.c.
Referenced by build_status(), pri_dchannel(), and pri_event_alarm().
| #define PRI_CHANNEL | ( | p | ) | ((p) & 0xff) |
Definition at line 94 of file sig_pri.c.
Referenced by pri_dchannel(), pri_find_principle(), sig_pri_handle_hold(), sig_pri_handle_retrieve(), and sig_pri_handle_subcmds().
| #define PRI_CIS_CALL (1 << 17) |
Definition at line 97 of file sig_pri.c.
Referenced by sig_pri_is_cis_call().
| #define PRI_DEADLOCK_AVOIDANCE | ( | p | ) |
do { \ sig_pri_unlock_private(p); \ usleep(1); \ sig_pri_lock_private(p); \ } while (0)
Definition at line 103 of file sig_pri.c.
Referenced by pri_grab(), and sig_pri_lock_owner().
| #define PRI_EXPLICIT (1 << 16) |
Definition at line 96 of file sig_pri.c.
Referenced by pri_find_principle(), and PVT_TO_CHANNEL().
| #define PRI_HELD_CALL (1 << 18) |
Definition at line 98 of file sig_pri.c.
Referenced by pri_find_principle(), and sig_pri_handle_retrieve().
| #define PRI_SPAN | ( | p | ) | (((p) >> 8) & 0xff) |
Definition at line 95 of file sig_pri.c.
Referenced by pri_dchannel(), pri_find_principle(), pri_maintenance_bservice(), sig_pri_handle_hold(), and sig_pri_handle_subcmds().
| typedef void(* xfer_rsp_callback)(void *data, int is_successful) |
Definition at line 6021 of file sig_pri.c.
{
OPT_ARG_KEYPAD = 0,
OPT_ARG_AOC_REQUEST,
/* note: this entry _MUST_ be the last one in the enum */
OPT_ARG_ARRAY_SIZE,
};
Definition at line 6016 of file sig_pri.c.
{
OPT_KEYPAD = (1 << 0),
OPT_REVERSE_CHARGE = (1 << 1), /* Collect call */
OPT_AOC_REQUEST = (1 << 2), /* AOC Request */
};
| static void apply_plan_to_number | ( | char * | buf, |
| size_t | size, | ||
| const struct sig_pri_span * | pri, | ||
| const char * | number, | ||
| const int | plan | ||
| ) | [static] |
Definition at line 1330 of file sig_pri.c.
References sig_pri_span::internationalprefix, sig_pri_span::localprefix, sig_pri_span::nationalprefix, sig_pri_span::privateprefix, and sig_pri_span::unknownprefix.
Referenced by pri_dchannel(), and sig_pri_party_number_convert().
{
switch (plan) {
case PRI_INTERNATIONAL_ISDN: /* Q.931 dialplan == 0x11 international dialplan => prepend international prefix digits */
snprintf(buf, size, "%s%s", pri->internationalprefix, number);
break;
case PRI_NATIONAL_ISDN: /* Q.931 dialplan == 0x21 national dialplan => prepend national prefix digits */
snprintf(buf, size, "%s%s", pri->nationalprefix, number);
break;
case PRI_LOCAL_ISDN: /* Q.931 dialplan == 0x41 local dialplan => prepend local prefix digits */
snprintf(buf, size, "%s%s", pri->localprefix, number);
break;
case PRI_PRIVATE: /* Q.931 dialplan == 0x49 private dialplan => prepend private prefix digits */
snprintf(buf, size, "%s%s", pri->privateprefix, number);
break;
case PRI_UNKNOWN: /* Q.931 dialplan == 0x00 unknown dialplan => prepend unknown prefix digits */
snprintf(buf, size, "%s%s", pri->unknownprefix, number);
break;
default: /* other Q.931 dialplan => don't twiddle with callingnum */
snprintf(buf, size, "%s", number);
break;
}
}
| static unsigned char ast_pri_pack_hex_char | ( | char | c | ) | [static] |
Definition at line 623 of file sig_pri.c.
Referenced by ast_pri_pack_hex_string().
{
unsigned char res;
if (c < '0') {
res = 0;
} else if (c < ('9' + 1)) {
res = c - '0';
} else if (c < 'A') {
res = 0;
} else if (c < ('F' + 1)) {
res = c - 'A' + 10;
} else if (c < 'a') {
res = 0;
} else if (c < ('f' + 1)) {
res = c - 'a' + 10;
} else {
res = 0;
}
return res;
}
| static int ast_pri_pack_hex_string | ( | unsigned char * | dst, |
| char * | src, | ||
| int | maxlen | ||
| ) | [static] |
Definition at line 662 of file sig_pri.c.
References ast_pri_pack_hex_char(), and len().
Referenced by sig_pri_party_subaddress_from_ast().
{
int res = 0;
int len = strlen(src);
if (len > (2 * maxlen)) {
len = 2 * maxlen;
}
res = len / 2 + len % 2;
while (len > 1) {
*dst = ast_pri_pack_hex_char(*src) << 4;
src++;
*dst |= ast_pri_pack_hex_char(*src);
dst++, src++;
len -= 2;
}
if (len) { /* 1 left */
*dst = ast_pri_pack_hex_char(*src) << 4;
}
return res;
}
| static int ast_to_pri_char_set | ( | enum AST_PARTY_CHAR_SET | ast_char_set | ) | [static] |
Definition at line 525 of file sig_pri.c.
References AST_PARTY_CHAR_SET_ISO10646_BMPSTRING, AST_PARTY_CHAR_SET_ISO10646_UTF_8STRING, AST_PARTY_CHAR_SET_ISO8859_1, AST_PARTY_CHAR_SET_ISO8859_2, AST_PARTY_CHAR_SET_ISO8859_3, AST_PARTY_CHAR_SET_ISO8859_4, AST_PARTY_CHAR_SET_ISO8859_5, AST_PARTY_CHAR_SET_ISO8859_7, AST_PARTY_CHAR_SET_UNKNOWN, and AST_PARTY_CHAR_SET_WITHDRAWN.
Referenced by sig_pri_party_name_from_ast().
{
int pri_char_set;
switch (ast_char_set) {
default:
case AST_PARTY_CHAR_SET_UNKNOWN:
pri_char_set = PRI_CHAR_SET_UNKNOWN;
break;
case AST_PARTY_CHAR_SET_ISO8859_1:
pri_char_set = PRI_CHAR_SET_ISO8859_1;
break;
case AST_PARTY_CHAR_SET_WITHDRAWN:
pri_char_set = PRI_CHAR_SET_WITHDRAWN;
break;
case AST_PARTY_CHAR_SET_ISO8859_2:
pri_char_set = PRI_CHAR_SET_ISO8859_2;
break;
case AST_PARTY_CHAR_SET_ISO8859_3:
pri_char_set = PRI_CHAR_SET_ISO8859_3;
break;
case AST_PARTY_CHAR_SET_ISO8859_4:
pri_char_set = PRI_CHAR_SET_ISO8859_4;
break;
case AST_PARTY_CHAR_SET_ISO8859_5:
pri_char_set = PRI_CHAR_SET_ISO8859_5;
break;
case AST_PARTY_CHAR_SET_ISO8859_7:
pri_char_set = PRI_CHAR_SET_ISO8859_7;
break;
case AST_PARTY_CHAR_SET_ISO10646_BMPSTRING:
pri_char_set = PRI_CHAR_SET_ISO10646_BMPSTRING;
break;
case AST_PARTY_CHAR_SET_ISO10646_UTF_8STRING:
pri_char_set = PRI_CHAR_SET_ISO10646_UTF_8STRING;
break;
}
return pri_char_set;
}
| static int ast_to_pri_presentation | ( | int | ast_presentation | ) | [static] |
Definition at line 426 of file sig_pri.c.
References AST_PRES_ALLOWED_NETWORK_NUMBER, AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, AST_PRES_NUMBER_NOT_AVAILABLE, AST_PRES_PROHIB_NETWORK_NUMBER, AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED, and AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN.
Referenced by sig_pri_party_name_from_ast(), and sig_pri_party_number_from_ast().
{
int pri_presentation;
switch (ast_presentation) {
case AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
pri_presentation = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
break;
case AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
pri_presentation = PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
break;
case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
pri_presentation = PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN;
break;
case AST_PRES_ALLOWED_NETWORK_NUMBER:
pri_presentation = PRES_ALLOWED_NETWORK_NUMBER;
break;
case AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
pri_presentation = PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
break;
case AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
pri_presentation = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
break;
case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
pri_presentation = PRES_PROHIB_USER_NUMBER_FAILED_SCREEN;
break;
case AST_PRES_PROHIB_NETWORK_NUMBER:
pri_presentation = PRES_PROHIB_NETWORK_NUMBER;
break;
case AST_PRES_NUMBER_NOT_AVAILABLE:
pri_presentation = PRES_NUMBER_NOT_AVAILABLE;
break;
default:
pri_presentation = PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
break;
}
return pri_presentation;
}
| static int ast_to_pri_reason | ( | enum AST_REDIRECTING_REASON | ast_reason | ) | [static] |
Definition at line 342 of file sig_pri.c.
References AST_REDIRECTING_REASON_DEFLECTION, AST_REDIRECTING_REASON_NO_ANSWER, AST_REDIRECTING_REASON_UNCONDITIONAL, AST_REDIRECTING_REASON_UNKNOWN, and AST_REDIRECTING_REASON_USER_BUSY.
Referenced by sig_pri_redirecting_update().
{
int pri_reason;
switch (ast_reason) {
case AST_REDIRECTING_REASON_USER_BUSY:
pri_reason = PRI_REDIR_FORWARD_ON_BUSY;
break;
case AST_REDIRECTING_REASON_NO_ANSWER:
pri_reason = PRI_REDIR_FORWARD_ON_NO_REPLY;
break;
case AST_REDIRECTING_REASON_UNCONDITIONAL:
pri_reason = PRI_REDIR_UNCONDITIONAL;
break;
case AST_REDIRECTING_REASON_DEFLECTION:
pri_reason = PRI_REDIR_DEFLECTION;
break;
case AST_REDIRECTING_REASON_UNKNOWN:
default:
pri_reason = PRI_REDIR_UNKNOWN;
break;
}
return pri_reason;
}
| static void build_status | ( | char * | s, |
| size_t | len, | ||
| int | status, | ||
| int | active | ||
| ) | [static] |
Definition at line 7250 of file sig_pri.c.
References DCHAN_NOTINALARM, and DCHAN_UP.
Referenced by sig_pri_cli_show_span(), and sig_pri_cli_show_spans().
{
if (!s || len < 1) {
return;
}
s[0] = '\0';
if (!(status & DCHAN_NOTINALARM))
strncat(s, "In Alarm, ", len - strlen(s) - 1);
if (status & DCHAN_UP)
strncat(s, "Up", len - strlen(s) - 1);
else
strncat(s, "Down", len - strlen(s) - 1);
if (active)
strncat(s, ", Active", len - strlen(s) - 1);
else
strncat(s, ", Standby", len - strlen(s) - 1);
s[len - 1] = '\0';
}
| static int detect_aoc_e_subcmd | ( | const struct pri_subcommands * | subcmds | ) | [static] |
Definition at line 3725 of file sig_pri.c.
Referenced by pri_dchannel().
{
int i;
if (!subcmds) {
return 0;
}
for (i = 0; i < subcmds->counter_subcmd; ++i) {
const struct pri_subcommand *subcmd = &subcmds->subcmd[i];
if (subcmd->cmd == PRI_SUBCMD_AOC_E) {
return 1;
}
}
return 0;
}
| static char* dialplan2str | ( | int | dialplan | ) | [static] |
Definition at line 1322 of file sig_pri.c.
Referenced by sig_pri_call().
{
if (dialplan == -1) {
return("Dynamically set dialplan in ISDN");
}
return (pri_plan2str(dialplan));
}
| static void* do_idle_thread | ( | void * | v_pvt | ) | [static] |
Definition at line 1514 of file sig_pri.c.
References ast_call(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, ast_copy_string(), AST_FRAME_CONTROL, ast_frfree, ast_hangup(), ast_log(), ast_pbx_run(), ast_read(), ast_verb, ast_waitfor(), sig_pri_chan::channel, ast_channel::context, ast_channel::exten, f, ast_frame::frametype, sig_pri_span::idlecontext, sig_pri_span::idledial, sig_pri_span::idleext, ast_frame_subclass::integer, LOG_WARNING, ast_channel::name, sig_pri_chan::owner, sig_pri_chan::pri, ast_channel::priority, and ast_frame::subclass.
Referenced by pri_dchannel().
{
struct sig_pri_chan *pvt = v_pvt;
struct ast_channel *chan = pvt->owner;
struct ast_frame *f;
char ex[80];
/* Wait up to 30 seconds for an answer */
int newms, ms = 30000;
ast_verb(3, "Initiating idle call on channel %s\n", chan->name);
snprintf(ex, sizeof(ex), "%d/%s", pvt->channel, pvt->pri->idledial);
if (ast_call(chan, ex, 0)) {
ast_log(LOG_WARNING, "Idle dial failed on '%s' to '%s'\n", chan->name, ex);
ast_hangup(chan);
return NULL;
}
while ((newms = ast_waitfor(chan, ms)) > 0) {
f = ast_read(chan);
if (!f) {
/* Got hangup */
break;
}
if (f->frametype == AST_FRAME_CONTROL) {
switch (f->subclass.integer) {
case AST_CONTROL_ANSWER:
/* Launch the PBX */
ast_copy_string(chan->exten, pvt->pri->idleext, sizeof(chan->exten));
ast_copy_string(chan->context, pvt->pri->idlecontext, sizeof(chan->context));
chan->priority = 1;
ast_verb(4, "Idle channel '%s' answered, sending to %s@%s\n", chan->name, chan->exten, chan->context);
ast_pbx_run(chan);
/* It's already hungup, return immediately */
return NULL;
case AST_CONTROL_BUSY:
ast_verb(4, "Idle channel '%s' busy, waiting...\n", chan->name);
break;
case AST_CONTROL_CONGESTION:
ast_verb(4, "Idle channel '%s' congested, waiting...\n", chan->name);
break;
};
}
ast_frfree(f);
ms = newms;
}
/* Hangup the channel since nothing happend */
ast_hangup(chan);
return NULL;
}
| static int pri_active_dchan_index | ( | struct sig_pri_span * | pri | ) | [static] |
Definition at line 953 of file sig_pri.c.
References ast_log(), sig_pri_span::dchans, LOG_WARNING, sig_pri_span::pri, and SIG_PRI_NUM_DCHANS.
Referenced by pri_find_principle().
{
int x;
for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
if ((pri->dchans[x] == pri->pri))
return x;
}
ast_log(LOG_WARNING, "No active dchan found!\n");
return -1;
}
| static int pri_check_restart | ( | struct sig_pri_span * | pri | ) | [static] |
Definition at line 1355 of file sig_pri.c.
References ast_log(), sig_pri_chan::call, sig_pri_chan::channel, sig_pri_span::lastreset, LOG_NOTICE, sig_pri_chan::no_b_channel, sig_pri_span::numchans, sig_pri_span::pri, PVT_TO_CHANNEL(), sig_pri_span::pvts, sig_pri_span::resetpos, sig_pri_span::resetting, sig_pri_chan::resetting, sig_pri_chan::service_status, sig_pri_span::span, SRVST_FAREND, and SRVST_NEAREND.
Referenced by pri_dchannel().
{
#if defined(HAVE_PRI_SERVICE_MESSAGES)
tryanotherpos:
#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
do {
pri->resetpos++;
} while (pri->resetpos < pri->numchans
&& (!pri->pvts[pri->resetpos]
|| pri->pvts[pri->resetpos]->no_b_channel
|| pri->pvts[pri->resetpos]->call
|| pri->pvts[pri->resetpos]->resetting));
if (pri->resetpos < pri->numchans) {
#if defined(HAVE_PRI_SERVICE_MESSAGES)
unsigned why;
why = pri->pvts[pri->resetpos]->service_status;
if (why) {
ast_log(LOG_NOTICE, "span '%d' channel '%d' out-of-service (reason: %s), not sending RESTART\n", pri->span,
pri->pvts[pri->resetpos]->channel, (why & SRVST_FAREND) ? (why & SRVST_NEAREND) ? "both ends" : "far end" : "near end");
goto tryanotherpos;
}
#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
/* Mark the channel as resetting and restart it */
pri->pvts[pri->resetpos]->resetting = 1;
pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[pri->resetpos]));
} else {
pri->resetting = 0;
time(&pri->lastreset);
}
return 0;
}
| static void* pri_dchannel | ( | void * | vpri | ) | [static] |
Definition at line 4233 of file sig_pri.c.
References ast_channel::_softhangup, ast_channel::_state, sig_pri_chan::alerting, sig_pri_span::allow_call_waiting_calls, sig_pri_chan::alreadyhungup, sig_pri_span::aoce_delayhangup, sig_pri_span::append_msn_to_user_tag, apply_plan_to_number(), ast_atomic_fetchadd_int(), ast_bridged_channel(), ast_canmatch_extension(), AST_CAUSE_USER_BUSY, AST_CC_CCBS, AST_CC_CCNR, ast_channel_unlock, AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_db_del(), ast_db_put(), ast_debug, ast_exists_extension(), AST_FORMAT_ULAW, AST_FRAME_DTMF, ast_hangup(), ast_log(), ast_matchmore_extension(), AST_MAX_EXTENSION, ast_mutex_lock, ast_mutex_unlock, ast_party_subaddress_free(), ast_party_subaddress_init(), ast_pbx_start(), ast_pthread_create_background, ast_pthread_create_detached, ast_shrink_phone_number(), AST_SOFTHANGUP_DEV, ast_softhangup_nolock(), AST_STATE_BUSY, AST_STATE_RESERVED, AST_STATE_RING, AST_STATE_UP, ast_strlen_zero(), ast_tv(), ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvsub(), ast_verb, ast_verbose(), sig_pri_chan::call, ast_channel::caller, sig_pri_chan::callingpres, sig_pri_chan::channel, sig_pri_chan::cid_ani, sig_pri_chan::cid_ani2, sig_pri_chan::cid_name, sig_pri_chan::cid_num, sig_pri_chan::cid_subaddr, sig_pri_chan::cid_ton, sig_pri_chan::context, dahdi_db, DAHDI_OVERLAPDIAL_INCOMING, ast_channel::data, DCHAN_UP, sig_pri_span::dchanavail, sig_pri_span::dchans, sig_pri_span::debug, detect_aoc_e_subcmd(), sig_pri_chan::dialdest, ast_channel::dialed, sig_pri_span::discardremoteholdretrieval, do_idle_thread(), errno, sig_pri_chan::exten, sig_pri_span::fds, ast_channel::hangupcause, sig_pri_span::hold_disconnect_transfer, sig_pri_chan::holding_aoce, ast_party_caller::id, sig_pri_span::idlecontext, sig_pri_span::idledial, sig_pri_span::idleext, sig_pri_chan::immediate, sig_pri_span::initial_user_tag, sig_pri_chan::is_call_waiting, sig_pri_chan::isidlecall, sig_pri_chan::keypad_digits, sig_pri_span::lastreset, sig_pri_span::lock, LOG_ERROR, LOG_NOTICE, LOG_WARNING, sig_pri_chan::logicalspan, sig_pri_span::minidle, sig_pri_span::minunused, sig_pri_span::msn_list, ast_channel::name, sig_pri_chan::no_b_channel, sig_pri_span::no_d_channels, sig_pri_span::nodetype, sig_pri_span::num_call_waiting_calls, sig_pri_span::numchans, sig_pri_chan::outgoing, sig_pri_span::overlapdial, sig_pri_chan::owner, pbx_builtin_setvar_helper(), sig_pri_chan::pri, sig_pri_span::pri, PRI_CHANNEL, pri_check_restart(), pri_find_dchan(), pri_find_empty_chan(), pri_find_empty_nobch(), pri_find_principle(), pri_fixup_principle(), pri_is_up(), pri_order(), pri_queue_control(), pri_queue_frame(), PRI_SPAN, pri_ss_thread(), sig_pri_chan::prioffset, sig_pri_chan::proceeding, sig_pri_chan::progress, PVT_TO_CHANNEL(), sig_pri_span::pvts, redirectingreason2str(), sig_pri_span::resetinterval, sig_pri_span::resetpos, sig_pri_chan::resetting, sig_pri_span::resetting, sig_pri_chan::reverse_charging_indication, S_OR, sig_pri_chan::service_status, sig_pri_chan::setup_ack, sig_pri_span::sig, SIG_BRI_PTMP, SIG_PRI_ALAW, sig_pri_attempt_transfer(), sig_pri_cc_generic_check(), sig_pri_handle_cis_subcmds(), sig_pri_handle_dchan_exception(), sig_pri_handle_hold(), sig_pri_handle_retrieve(), sig_pri_handle_subcmds(), sig_pri_init_config(), sig_pri_is_cis_call(), sig_pri_lock_owner(), sig_pri_lock_private(), sig_pri_msn_match(), sig_pri_new_ast_channel(), SIG_PRI_NUM_DCHANS, sig_pri_open_media(), sig_pri_request(), sig_pri_send_aoce_termination_request(), sig_pri_set_alarm(), sig_pri_set_caller_id(), sig_pri_set_dialing(), sig_pri_set_dnid(), sig_pri_set_echocanceller(), sig_pri_set_rdnis(), sig_pri_set_subaddress(), sig_pri_span_devstate_changed(), SIG_PRI_ULAW, sig_pri_unlock_private(), sig_pri_span::span, SRVST_DBKEY, SRVST_FAREND, SRVST_NEAREND, SRVST_TYPE_OOS, ast_party_subaddress::str, ast_party_dialed::subaddress, ast_party_id::subaddress, sig_pri_span::switchtype, sig_pri_chan::use_callerid, and sig_pri_chan::user_tag.
Referenced by sig_pri_start_pri().
{
struct sig_pri_span *pri = vpri;
pri_event *e;
struct pollfd fds[SIG_PRI_NUM_DCHANS];
int res;
int chanpos = 0;
int x;
struct ast_channel *c;
struct timeval tv, lowest, *next;
int doidling=0;
char *cc;
time_t t;
int i, which=-1;
int numdchans;
pthread_t threadid;
char ani2str[6];
char plancallingnum[AST_MAX_EXTENSION];
char plancallingani[AST_MAX_EXTENSION];
char calledtonstr[10];
struct timeval lastidle = { 0, 0 };
pthread_t p;
struct ast_channel *idle;
char idlen[80];
int nextidle = -1;
int haveidles;
int activeidles;
gettimeofday(&lastidle, NULL);
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
if (!ast_strlen_zero(pri->idledial) && !ast_strlen_zero(pri->idleext)) {
/* Need to do idle dialing, check to be sure though */
cc = strchr(pri->idleext, '@');
if (cc) {
*cc = '\0';
cc++;
ast_copy_string(pri->idlecontext, cc, sizeof(pri->idlecontext));
#if 0
/* Extensions may not be loaded yet */
if (!ast_exists_extension(NULL, pri->idlecontext, pri->idleext, 1, NULL))
ast_log(LOG_WARNING, "Extension '%s @ %s' does not exist\n", pri->idleext, pri->idlecontext);
else
#endif
doidling = 1;
} else
ast_log(LOG_WARNING, "Idle dial string '%s' lacks '@context'\n", pri->idleext);
}
for (;;) {
for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
if (!pri->dchans[i])
break;
fds[i].fd = pri->fds[i];
fds[i].events = POLLIN | POLLPRI;
fds[i].revents = 0;
}
numdchans = i;
time(&t);
ast_mutex_lock(&pri->lock);
if (pri->switchtype != PRI_SWITCH_GR303_TMC && (pri->sig != SIG_BRI_PTMP) && (pri->resetinterval > 0)) {
if (pri->resetting && pri_is_up(pri)) {
if (pri->resetpos < 0)
pri_check_restart(pri);
} else {
if (!pri->resetting && (t - pri->lastreset) >= pri->resetinterval) {
pri->resetting = 1;
pri->resetpos = -1;
}
}
}
/* Look for any idle channels if appropriate */
if (doidling && pri_is_up(pri)) {
nextidle = -1;
haveidles = 0;
activeidles = 0;
for (x = pri->numchans; x >= 0; x--) {
if (pri->pvts[x]
&& !pri->pvts[x]->owner
&& !pri->pvts[x]->call
&& !pri->pvts[x]->no_b_channel) {
if (haveidles < pri->minunused) {
haveidles++;
} else if (!pri->pvts[x]->resetting) {
nextidle = x;
break;
}
} else if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall)
activeidles++;
}
if (nextidle > -1) {
if (ast_tvdiff_ms(ast_tvnow(), lastidle) > 1000) {
/* Don't create a new idle call more than once per second */
snprintf(idlen, sizeof(idlen), "%d/%s", pri->pvts[nextidle]->channel, pri->idledial);
idle = sig_pri_request(pri->pvts[nextidle], AST_FORMAT_ULAW, NULL, 0);
if (idle) {
pri->pvts[nextidle]->isidlecall = 1;
if (ast_pthread_create_background(&p, NULL, do_idle_thread, pri->pvts[nextidle])) {
ast_log(LOG_WARNING, "Unable to start new thread for idle channel '%s'\n", idle->name);
ast_hangup(idle);
}
} else
ast_log(LOG_WARNING, "Unable to request channel 'DAHDI/%s' for idle call\n", idlen);
gettimeofday(&lastidle, NULL);
}
} else if ((haveidles < pri->minunused) &&
(activeidles > pri->minidle)) {
/* Mark something for hangup if there is something
that can be hungup */
for (x = pri->numchans; x >= 0; x--) {
/* find a candidate channel */
if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall) {
pri->pvts[x]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
haveidles++;
/* Stop if we have enough idle channels or
can't spare any more active idle ones */
if ((haveidles >= pri->minunused) ||
(activeidles <= pri->minidle))
break;
}
}
}
}
/* Start with reasonable max */
if (doidling || pri->resetting) {
/*
* Make sure we stop at least once per second if we're
* monitoring idle channels
*/
lowest = ast_tv(1, 0);
} else {
/* Don't poll for more than 60 seconds */
lowest = ast_tv(60, 0);
}
for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
if (!pri->dchans[i]) {
/* We scanned all D channels on this span. */
break;
}
next = pri_schedule_next(pri->dchans[i]);
if (next) {
/* We need relative time here */
tv = ast_tvsub(*next, ast_tvnow());
if (tv.tv_sec < 0) {
/*
* A timer has already expired.
* By definition zero time is the lowest so we can quit early.
*/
lowest = ast_tv(0, 0);
break;
}
if (ast_tvcmp(tv, lowest) < 0) {
lowest = tv;
}
}
}
ast_mutex_unlock(&pri->lock);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_testcancel();
e = NULL;
res = poll(fds, numdchans, lowest.tv_sec * 1000 + lowest.tv_usec / 1000);
pthread_testcancel();
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
ast_mutex_lock(&pri->lock);
if (!res) {
for (which = 0; which < SIG_PRI_NUM_DCHANS; which++) {
if (!pri->dchans[which])
break;
/* Just a timeout, run the scheduler */
e = pri_schedule_run(pri->dchans[which]);
if (e)
break;
}
} else if (res > -1) {
for (which = 0; which < SIG_PRI_NUM_DCHANS; which++) {
if (!pri->dchans[which])
break;
if (fds[which].revents & POLLPRI) {
sig_pri_handle_dchan_exception(pri, which);
} else if (fds[which].revents & POLLIN) {
e = pri_check_event(pri->dchans[which]);
}
if (e)
break;
}
} else if (errno != EINTR)
ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));
if (e) {
if (pri->debug) {
ast_verbose("Span: %d Processing event: %s\n",
pri->span, pri_event2str(e->e));
}
if (e->e != PRI_EVENT_DCHAN_DOWN) {
if (!(pri->dchanavail[which] & DCHAN_UP)) {
ast_verb(2, "%s D-Channel on span %d up\n", pri_order(which), pri->span);
}
pri->dchanavail[which] |= DCHAN_UP;
} else {
if (pri->dchanavail[which] & DCHAN_UP) {
ast_verb(2, "%s D-Channel on span %d down\n", pri_order(which), pri->span);
}
pri->dchanavail[which] &= ~DCHAN_UP;
}
if ((e->e != PRI_EVENT_DCHAN_UP) && (e->e != PRI_EVENT_DCHAN_DOWN) && (pri->pri != pri->dchans[which]))
/* Must be an NFAS group that has the secondary dchan active */
pri->pri = pri->dchans[which];
switch (e->e) {
case PRI_EVENT_DCHAN_UP:
pri->no_d_channels = 0;
if (!pri->pri) pri_find_dchan(pri);
/* Note presense of D-channel */
time(&pri->lastreset);
/* Restart in 5 seconds */
if (pri->resetinterval > -1) {
pri->lastreset -= pri->resetinterval;
pri->lastreset += 5;
}
pri->resetting = 0;
/* Take the channels from inalarm condition */
for (i = 0; i < pri->numchans; i++) {
if (pri->pvts[i]) {
sig_pri_set_alarm(pri->pvts[i], 0);
}
}
sig_pri_span_devstate_changed(pri);
break;
case PRI_EVENT_DCHAN_DOWN:
pri_find_dchan(pri);
if (!pri_is_up(pri)) {
pri->resetting = 0;
if (pri->sig == SIG_BRI_PTMP) {
/* For PTMP connections with non persistent layer 2 we want
* to *not* declare inalarm unless there actually is an alarm */
break;
}
/* Hangup active channels and put them in alarm mode */
for (i = 0; i < pri->numchans; i++) {
struct sig_pri_chan *p = pri->pvts[i];
if (p) {
if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
/* T309 is not enabled : hangup calls when alarm occurs */
if (p->call) {
if (p->pri && p->pri->pri) {
pri_hangup(p->pri->pri, p->call, -1);
pri_destroycall(p->pri->pri, p->call);
p->call = NULL;
} else
ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
}
if (p->owner)
p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
}
sig_pri_set_alarm(p, 1);
}
}
sig_pri_span_devstate_changed(pri);
}
break;
case PRI_EVENT_RESTART:
if (e->restart.channel > -1) {
chanpos = pri_find_principle(pri, e->restart.channel, NULL);
if (chanpos < 0)
ast_log(LOG_WARNING, "Restart requested on odd/unavailable channel number %d/%d on span %d\n",
PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
else {
int skipit = 0;
#if defined(HAVE_PRI_SERVICE_MESSAGES)
unsigned why;
why = pri->pvts[chanpos]->service_status;
if (why) {
ast_log(LOG_NOTICE,
"span '%d' channel '%d' out-of-service (reason: %s), ignoring RESTART\n",
pri->span, PRI_CHANNEL(e->restart.channel),
(why & SRVST_FAREND) ? (why & SRVST_NEAREND) ? "both ends" : "far end" : "near end");
skipit = 1;
}
#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
sig_pri_lock_private(pri->pvts[chanpos]);
if (!skipit) {
ast_verb(3, "B-channel %d/%d restarted on span %d\n",
PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
if (pri->pvts[chanpos]->call) {
pri_destroycall(pri->pri, pri->pvts[chanpos]->call);
pri->pvts[chanpos]->call = NULL;
}
}
/* Force soft hangup if appropriate */
if (pri->pvts[chanpos]->owner)
pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
sig_pri_unlock_private(pri->pvts[chanpos]);
}
} else {
ast_verb(3, "Restart requested on entire span %d\n", pri->span);
for (x = 0; x < pri->numchans; x++)
if (pri->pvts[x]) {
sig_pri_lock_private(pri->pvts[x]);
if (pri->pvts[x]->call) {
pri_destroycall(pri->pri, pri->pvts[x]->call);
pri->pvts[x]->call = NULL;
}
if (pri->pvts[x]->owner)
pri->pvts[x]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
sig_pri_unlock_private(pri->pvts[x]);
}
}
break;
case PRI_EVENT_KEYPAD_DIGIT:
if (sig_pri_is_cis_call(e->digit.channel)) {
sig_pri_handle_cis_subcmds(pri, e->e, e->digit.subcmds,
e->digit.call);
break;
}
chanpos = pri_find_principle(pri, e->digit.channel, e->digit.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "KEYPAD_DIGITs received on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->digit.channel), PRI_CHANNEL(e->digit.channel), pri->span);
} else {
chanpos = pri_fixup_principle(pri, chanpos, e->digit.call);
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->digit.channel,
e->digit.subcmds, e->digit.call);
/* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */
if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
&& pri->pvts[chanpos]->call == e->digit.call
&& pri->pvts[chanpos]->owner) {
/* how to do that */
int digitlen = strlen(e->digit.digits);
int i;
for (i = 0; i < digitlen; i++) {
struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = e->digit.digits[i], };
pri_queue_frame(pri, chanpos, &f);
}
}
sig_pri_unlock_private(pri->pvts[chanpos]);
}
}
break;
case PRI_EVENT_INFO_RECEIVED:
if (sig_pri_is_cis_call(e->ring.channel)) {
sig_pri_handle_cis_subcmds(pri, e->e, e->ring.subcmds,
e->ring.call);
break;
}
chanpos = pri_find_principle(pri, e->ring.channel, e->ring.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "INFO received on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
} else {
chanpos = pri_fixup_principle(pri, chanpos, e->ring.call);
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
e->ring.subcmds, e->ring.call);
/* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
&& pri->pvts[chanpos]->call == e->ring.call
&& pri->pvts[chanpos]->owner) {
/* how to do that */
int digitlen = strlen(e->ring.callednum);
int i;
for (i = 0; i < digitlen; i++) {
struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = e->ring.callednum[i], };
pri_queue_frame(pri, chanpos, &f);
}
}
sig_pri_unlock_private(pri->pvts[chanpos]);
}
}
break;
#if defined(HAVE_PRI_SERVICE_MESSAGES)
case PRI_EVENT_SERVICE:
chanpos = pri_find_principle(pri, e->service.channel, NULL);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Received service change status %d on unconfigured channel %d/%d span %d\n",
e->service_ack.changestatus, PRI_SPAN(e->service_ack.channel), PRI_CHANNEL(e->service_ack.channel), pri->span);
} else {
char db_chan_name[20];
char db_answer[5];
int ch;
unsigned *why;
ch = pri->pvts[chanpos]->channel;
snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, pri->span, ch);
why = &pri->pvts[chanpos]->service_status;
switch (e->service.changestatus) {
case 0: /* in-service */
/* Far end wants to be in service now. */
ast_db_del(db_chan_name, SRVST_DBKEY);
*why &= ~SRVST_FAREND;
if (*why) {
snprintf(db_answer, sizeof(db_answer), "%s:%u",
SRVST_TYPE_OOS, *why);
ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
} else {
sig_pri_span_devstate_changed(pri);
}
break;
case 2: /* out-of-service */
/* Far end wants to be out-of-service now. */
ast_db_del(db_chan_name, SRVST_DBKEY);
*why |= SRVST_FAREND;
snprintf(db_answer, sizeof(db_answer), "%s:%u", SRVST_TYPE_OOS,
*why);
ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
sig_pri_span_devstate_changed(pri);
break;
default:
ast_log(LOG_ERROR, "Huh? changestatus is: %d\n", e->service.changestatus);
break;
}
ast_log(LOG_NOTICE, "Channel %d/%d span %d (logical: %d) received a change of service message, status '%d'\n",
PRI_SPAN(e->service.channel), PRI_CHANNEL(e->service.channel), pri->span, ch, e->service.changestatus);
}
break;
case PRI_EVENT_SERVICE_ACK:
chanpos = pri_find_principle(pri, e->service_ack.channel, NULL);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Received service acknowledge change status '%d' on unconfigured channel %d/%d span %d\n",
e->service_ack.changestatus, PRI_SPAN(e->service_ack.channel), PRI_CHANNEL(e->service_ack.channel), pri->span);
} else {
ast_debug(2, "Channel %d/%d span %d received a change os service acknowledgement message, status '%d'\n",
PRI_SPAN(e->service_ack.channel), PRI_CHANNEL(e->service_ack.channel), pri->span, e->service_ack.changestatus);
}
break;
#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
case PRI_EVENT_RING:
if (!ast_strlen_zero(pri->msn_list)
&& !sig_pri_msn_match(pri->msn_list, e->ring.callednum)) {
/* The call is not for us so ignore it. */
ast_verb(3,
"Ignoring call to '%s' on span %d. Its not in the MSN list: %s\n",
e->ring.callednum, pri->span, pri->msn_list);
pri_destroycall(pri->pri, e->ring.call);
break;
}
if (sig_pri_is_cis_call(e->ring.channel)) {
sig_pri_handle_cis_subcmds(pri, e->e, e->ring.subcmds,
e->ring.call);
break;
}
if (e->ring.channel == -1 || PRI_CHANNEL(e->ring.channel) == 0xFF) {
/* Any channel requested. */
chanpos = pri_find_empty_chan(pri, 1);
} else if (PRI_CHANNEL(e->ring.channel) == 0x00) {
/* No channel specified. */
#if defined(HAVE_PRI_CALL_WAITING)
if (!pri->allow_call_waiting_calls)
#endif /* defined(HAVE_PRI_CALL_WAITING) */
{
/* We will not accept incoming call waiting calls. */
pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INCOMPATIBLE_DESTINATION);
break;
}
#if defined(HAVE_PRI_CALL_WAITING)
chanpos = pri_find_empty_nobch(pri);
if (chanpos < 0) {
/* We could not find/create a call interface. */
pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
break;
}
/* Setup the call interface to use. */
sig_pri_init_config(pri->pvts[chanpos], pri);
#endif /* defined(HAVE_PRI_CALL_WAITING) */
} else {
/* A channel is specified. */
chanpos = pri_find_principle(pri, e->ring.channel, e->ring.call);
}
/* if no channel specified find one empty */
if (chanpos < 0) {
ast_log(LOG_WARNING, "Ring requested on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
} else {
sig_pri_lock_private(pri->pvts[chanpos]);
if (pri->pvts[chanpos]->owner) {
if (pri->pvts[chanpos]->call == e->ring.call) {
ast_log(LOG_WARNING, "Duplicate setup requested on channel %d/%d already in use on span %d\n",
PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
sig_pri_unlock_private(pri->pvts[chanpos]);
break;
} else {
/* This is where we handle initial glare */
ast_debug(1, "Ring requested on channel %d/%d already in use or previously requested on span %d. Attempting to renegotiating channel.\n",
PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
sig_pri_unlock_private(pri->pvts[chanpos]);
chanpos = -1;
}
}
if (chanpos > -1)
sig_pri_unlock_private(pri->pvts[chanpos]);
}
if ((chanpos < 0) && (e->ring.flexible))
chanpos = pri_find_empty_chan(pri, 1);
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
pri->pvts[chanpos]->call = e->ring.call;
/* Use plancallingnum as a scratch buffer since it is initialized next. */
apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri,
e->ring.redirectingnum, e->ring.callingplanrdnis);
sig_pri_set_rdnis(pri->pvts[chanpos], plancallingnum);
/* Setup caller-id info */
apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
pri->pvts[chanpos]->cid_ani2 = 0;
if (pri->pvts[chanpos]->use_callerid) {
ast_shrink_phone_number(plancallingnum);
ast_copy_string(pri->pvts[chanpos]->cid_num, plancallingnum, sizeof(pri->pvts[chanpos]->cid_num));
#ifdef PRI_ANI
if (!ast_strlen_zero(e->ring.callingani)) {
apply_plan_to_number(plancallingani, sizeof(plancallingani), pri, e->ring.callingani, e->ring.callingplanani);
ast_shrink_phone_number(plancallingani);
ast_copy_string(pri->pvts[chanpos]->cid_ani, plancallingani, sizeof(pri->pvts[chanpos]->cid_ani));
} else {
pri->pvts[chanpos]->cid_ani[0] = '\0';
}
#endif
pri->pvts[chanpos]->cid_subaddr[0] = '\0';
#if defined(HAVE_PRI_SUBADDR)
if (e->ring.calling.subaddress.valid) {
struct ast_party_subaddress calling_subaddress;
ast_party_subaddress_init(&calling_subaddress);
sig_pri_set_subaddress(&calling_subaddress,
&e->ring.calling.subaddress);
if (calling_subaddress.str) {
ast_copy_string(pri->pvts[chanpos]->cid_subaddr,
calling_subaddress.str,
sizeof(pri->pvts[chanpos]->cid_subaddr));
}
ast_party_subaddress_free(&calling_subaddress);
}
#endif /* defined(HAVE_PRI_SUBADDR) */
ast_copy_string(pri->pvts[chanpos]->cid_name, e->ring.callingname, sizeof(pri->pvts[chanpos]->cid_name));
pri->pvts[chanpos]->cid_ton = e->ring.callingplan; /* this is the callingplan (TON/NPI), e->ring.callingplan>>4 would be the TON */
pri->pvts[chanpos]->callingpres = e->ring.callingpres;
if (e->ring.ani2 >= 0) {
pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
}
} else {
pri->pvts[chanpos]->cid_num[0] = '\0';
pri->pvts[chanpos]->cid_subaddr[0] = '\0';
pri->pvts[chanpos]->cid_ani[0] = '\0';
pri->pvts[chanpos]->cid_name[0] = '\0';
pri->pvts[chanpos]->cid_ton = 0;
pri->pvts[chanpos]->callingpres = 0;
}
/* Setup the user tag for party id's from this device for this call. */
if (pri->append_msn_to_user_tag) {
snprintf(pri->pvts[chanpos]->user_tag,
sizeof(pri->pvts[chanpos]->user_tag), "%s_%s",
pri->initial_user_tag,
pri->nodetype == PRI_NETWORK
? plancallingnum : e->ring.callednum);
} else {
ast_copy_string(pri->pvts[chanpos]->user_tag,
pri->initial_user_tag, sizeof(pri->pvts[chanpos]->user_tag));
}
sig_pri_set_caller_id(pri->pvts[chanpos]);
/* Set DNID on all incoming calls -- even immediate */
sig_pri_set_dnid(pri->pvts[chanpos], e->ring.callednum);
/* If immediate=yes go to s|1 */
if (pri->pvts[chanpos]->immediate) {
ast_verb(3, "Going to extension s|1 because of immediate=yes\n");
pri->pvts[chanpos]->exten[0] = 's';
pri->pvts[chanpos]->exten[1] = '\0';
}
/* Get called number */
else if (!ast_strlen_zero(e->ring.callednum)) {
ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
} else if (pri->overlapdial)
pri->pvts[chanpos]->exten[0] = '\0';
else {
/* Some PRI circuits are set up to send _no_ digits. Handle them as 's'. */
pri->pvts[chanpos]->exten[0] = 's';
pri->pvts[chanpos]->exten[1] = '\0';
}
/* No number yet, but received "sending complete"? */
if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
ast_verb(3, "Going to extension s|1 because of Complete received\n");
pri->pvts[chanpos]->exten[0] = 's';
pri->pvts[chanpos]->exten[1] = '\0';
}
/* Make sure extension exists (or in overlap dial mode, can exist) */
if (((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
/* Setup law */
if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
/* Just announce proceeding */
pri->pvts[chanpos]->proceeding = 1;
pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
} else {
if (pri->switchtype != PRI_SWITCH_GR303_TMC)
pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
else
pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
}
/* Start PBX */
if (!e->ring.complete
&& (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
&& ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
/*
* Release the PRI lock while we create the channel
* so other threads can send D channel messages.
*/
ast_mutex_unlock(&pri->lock);
c = sig_pri_new_ast_channel(pri->pvts[chanpos],
AST_STATE_RESERVED,
(e->ring.layer1 == PRI_LAYER_1_ALAW)
? SIG_PRI_ALAW : SIG_PRI_ULAW,
e->ring.ctype, pri->pvts[chanpos]->exten, NULL);
ast_mutex_lock(&pri->lock);
if (c) {
#if defined(HAVE_PRI_SUBADDR)
if (e->ring.calling.subaddress.valid) {
/* Set Calling Subaddress */
sig_pri_lock_owner(pri, chanpos);
sig_pri_set_subaddress(
&pri->pvts[chanpos]->owner->caller.id.subaddress,
&e->ring.calling.subaddress);
if (!e->ring.calling.subaddress.type
&& !ast_strlen_zero(
(char *) e->ring.calling.subaddress.data)) {
/* NSAP */
pbx_builtin_setvar_helper(c, "CALLINGSUBADDR",
(char *) e->ring.calling.subaddress.data);
}
ast_channel_unlock(c);
}
if (e->ring.called_subaddress.valid) {
/* Set Called Subaddress */
sig_pri_lock_owner(pri, chanpos);
sig_pri_set_subaddress(
&pri->pvts[chanpos]->owner->dialed.subaddress,
&e->ring.called_subaddress);
if (!e->ring.called_subaddress.type
&& !ast_strlen_zero(
(char *) e->ring.called_subaddress.data)) {
/* NSAP */
pbx_builtin_setvar_helper(c, "CALLEDSUBADDR",
(char *) e->ring.called_subaddress.data);
}
ast_channel_unlock(c);
}
#else
if (!ast_strlen_zero(e->ring.callingsubaddr)) {
pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
}
#endif /* !defined(HAVE_PRI_SUBADDR) */
if (e->ring.ani2 >= 0) {
snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
pbx_builtin_setvar_helper(c, "ANI2", ani2str);
}
#ifdef SUPPORT_USERUSER
if (!ast_strlen_zero(e->ring.useruserinfo)) {
pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
}
#endif
snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
if (e->ring.redirectingreason >= 0) {
/* This is now just a status variable. Use REDIRECTING() dialplan function. */
pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
}
#if defined(HAVE_PRI_REVERSE_CHARGE)
pri->pvts[chanpos]->reverse_charging_indication = e->ring.reversecharge;
#endif
#if defined(HAVE_PRI_SETUP_KEYPAD)
ast_copy_string(pri->pvts[chanpos]->keypad_digits,
e->ring.keypad_digits,
sizeof(pri->pvts[chanpos]->keypad_digits));
#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
e->ring.subcmds, e->ring.call);
}
if (c && !ast_pthread_create_detached(&threadid, NULL, pri_ss_thread, pri->pvts[chanpos])) {
ast_verb(3, "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
} else {
ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
if (c)
ast_hangup(c);
else {
pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
pri->pvts[chanpos]->call = NULL;
}
}
} else {
/*
* Release the PRI lock while we create the channel
* so other threads can send D channel messages.
*/
ast_mutex_unlock(&pri->lock);
c = sig_pri_new_ast_channel(pri->pvts[chanpos],
AST_STATE_RING,
(e->ring.layer1 == PRI_LAYER_1_ALAW)
? SIG_PRI_ALAW : SIG_PRI_ULAW, e->ring.ctype,
pri->pvts[chanpos]->exten, NULL);
ast_mutex_lock(&pri->lock);
if (c) {
/*
* It is reasonably safe to set the following
* channel variables while the PRI and DAHDI private
* structures are locked. The PBX has not been
* started yet and it is unlikely that any other task
* will do anything with the channel we have just
* created.
*/
#if defined(HAVE_PRI_SUBADDR)
if (e->ring.calling.subaddress.valid) {
/* Set Calling Subaddress */
sig_pri_lock_owner(pri, chanpos);
sig_pri_set_subaddress(
&pri->pvts[chanpos]->owner->caller.id.subaddress,
&e->ring.calling.subaddress);
if (!e->ring.calling.subaddress.type
&& !ast_strlen_zero(
(char *) e->ring.calling.subaddress.data)) {
/* NSAP */
pbx_builtin_setvar_helper(c, "CALLINGSUBADDR",
(char *) e->ring.calling.subaddress.data);
}
ast_channel_unlock(c);
}
if (e->ring.called_subaddress.valid) {
/* Set Called Subaddress */
sig_pri_lock_owner(pri, chanpos);
sig_pri_set_subaddress(
&pri->pvts[chanpos]->owner->dialed.subaddress,
&e->ring.called_subaddress);
if (!e->ring.called_subaddress.type
&& !ast_strlen_zero(
(char *) e->ring.called_subaddress.data)) {
/* NSAP */
pbx_builtin_setvar_helper(c, "CALLEDSUBADDR",
(char *) e->ring.called_subaddress.data);
}
ast_channel_unlock(c);
}
#else
if (!ast_strlen_zero(e->ring.callingsubaddr)) {
pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
}
#endif /* !defined(HAVE_PRI_SUBADDR) */
if (e->ring.ani2 >= 0) {
snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
pbx_builtin_setvar_helper(c, "ANI2", ani2str);
}
#ifdef SUPPORT_USERUSER
if (!ast_strlen_zero(e->ring.useruserinfo)) {
pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
}
#endif
if (e->ring.redirectingreason >= 0) {
/* This is now just a status variable. Use REDIRECTING() dialplan function. */
pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
}
#if defined(HAVE_PRI_REVERSE_CHARGE)
pri->pvts[chanpos]->reverse_charging_indication = e->ring.reversecharge;
#endif
#if defined(HAVE_PRI_SETUP_KEYPAD)
ast_copy_string(pri->pvts[chanpos]->keypad_digits,
e->ring.keypad_digits,
sizeof(pri->pvts[chanpos]->keypad_digits));
#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
e->ring.subcmds, e->ring.call);
}
if (c && !ast_pbx_start(c)) {
ast_verb(3, "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
plancallingnum, pri->pvts[chanpos]->exten,
pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
} else {
ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
if (c) {
ast_hangup(c);
} else {
pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
pri->pvts[chanpos]->call = NULL;
}
}
}
} else {
ast_verb(3, "Extension '%s' in context '%s' from '%s' does not exist. Rejecting call on channel %d/%d, span %d\n",
pri->pvts[chanpos]->exten, pri->pvts[chanpos]->context, pri->pvts[chanpos]->cid_num, pri->pvts[chanpos]->logicalspan,
pri->pvts[chanpos]->prioffset, pri->span);
pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED);
pri->pvts[chanpos]->call = NULL;
pri->pvts[chanpos]->exten[0] = '\0';
}
sig_pri_unlock_private(pri->pvts[chanpos]);
} else {
if (e->ring.flexible)
pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
else
pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
}
break;
case PRI_EVENT_RINGING:
if (sig_pri_is_cis_call(e->ringing.channel)) {
sig_pri_handle_cis_subcmds(pri, e->e, e->ringing.subcmds,
e->ringing.call);
break;
}
chanpos = pri_find_principle(pri, e->ringing.channel, e->ringing.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Ringing requested on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span);
} else {
chanpos = pri_fixup_principle(pri, chanpos, e->ringing.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Ringing requested on channel %d/%d not in use on span %d\n",
PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span);
} else {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->ringing.channel,
e->ringing.subcmds, e->ringing.call);
sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCNR);
sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
pri_queue_control(pri, chanpos, AST_CONTROL_RINGING);
pri->pvts[chanpos]->alerting = 1;
if (
#ifdef PRI_PROGRESS_MASK
e->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE
#else
e->ringing.progress == 8
#endif
) {
sig_pri_open_media(pri->pvts[chanpos]);
}
#ifdef SUPPORT_USERUSER
if (!ast_strlen_zero(e->ringing.useruserinfo)) {
struct ast_channel *owner;
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
pbx_builtin_setvar_helper(owner, "USERUSERINFO",
e->ringing.useruserinfo);
ast_channel_unlock(owner);
}
}
#endif
sig_pri_unlock_private(pri->pvts[chanpos]);
}
}
break;
case PRI_EVENT_PROGRESS:
if (sig_pri_is_cis_call(e->proceeding.channel)) {
sig_pri_handle_cis_subcmds(pri, e->e, e->proceeding.subcmds,
e->proceeding.call);
break;
}
chanpos = pri_find_principle(pri, e->proceeding.channel, e->proceeding.call);
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->proceeding.channel,
e->proceeding.subcmds, e->proceeding.call);
if (e->proceeding.cause > -1) {
ast_verb(3, "PROGRESS with cause code %d received\n", e->proceeding.cause);
/* Work around broken, out of spec USER_BUSY cause in a progress message */
if (e->proceeding.cause == AST_CAUSE_USER_BUSY) {
if (pri->pvts[chanpos]->owner) {
ast_verb(3, "PROGRESS with 'user busy' received, signaling AST_CONTROL_BUSY instead of AST_CONTROL_PROGRESS\n");
pri->pvts[chanpos]->owner->hangupcause = e->proceeding.cause;
pri_queue_control(pri, chanpos, AST_CONTROL_BUSY);
}
}
}
if (!pri->pvts[chanpos]->progress
&& !pri->pvts[chanpos]->no_b_channel
#ifdef PRI_PROGRESS_MASK
&& (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)
#else
&& e->proceeding.progress == 8
#endif
) {
/* Bring voice path up */
ast_debug(1, "Queuing frame from PRI_EVENT_PROGRESS on channel %d/%d span %d\n",
pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
pri->pvts[chanpos]->progress = 1;
sig_pri_set_dialing(pri->pvts[chanpos], 0);
sig_pri_open_media(pri->pvts[chanpos]);
}
sig_pri_unlock_private(pri->pvts[chanpos]);
}
break;
case PRI_EVENT_PROCEEDING:
if (sig_pri_is_cis_call(e->proceeding.channel)) {
sig_pri_handle_cis_subcmds(pri, e->e, e->proceeding.subcmds,
e->proceeding.call);
break;
}
chanpos = pri_find_principle(pri, e->proceeding.channel, e->proceeding.call);
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->proceeding.channel,
e->proceeding.subcmds, e->proceeding.call);
if (!pri->pvts[chanpos]->proceeding) {
ast_debug(1, "Queuing frame from PRI_EVENT_PROCEEDING on channel %d/%d span %d\n",
pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
pri_queue_control(pri, chanpos, AST_CONTROL_PROCEEDING);
pri->pvts[chanpos]->proceeding = 1;
}
if (!pri->pvts[chanpos]->progress
&& !pri->pvts[chanpos]->no_b_channel
#ifdef PRI_PROGRESS_MASK
&& (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)
#else
&& e->proceeding.progress == 8
#endif
) {
/* Bring voice path up */
pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
pri->pvts[chanpos]->progress = 1;
sig_pri_set_dialing(pri->pvts[chanpos], 0);
sig_pri_open_media(pri->pvts[chanpos]);
}
sig_pri_unlock_private(pri->pvts[chanpos]);
}
break;
case PRI_EVENT_FACILITY:
if (!e->facility.call || sig_pri_is_cis_call(e->facility.channel)) {
/* Event came in on the dummy channel or a CIS call. */
#if defined(HAVE_PRI_CALL_REROUTING)
sig_pri_handle_cis_subcmds(pri, e->e, e->facility.subcmds,
e->facility.subcall);
#else
sig_pri_handle_cis_subcmds(pri, e->e, e->facility.subcmds,
e->facility.call);
#endif /* !defined(HAVE_PRI_CALL_REROUTING) */
break;
}
chanpos = pri_find_principle(pri, e->facility.channel, e->facility.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Facility requested on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->facility.channel), PRI_CHANNEL(e->facility.channel), pri->span);
} else {
chanpos = pri_fixup_principle(pri, chanpos, e->facility.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Facility requested on channel %d/%d not in use on span %d\n",
PRI_SPAN(e->facility.channel), PRI_CHANNEL(e->facility.channel), pri->span);
} else {
sig_pri_lock_private(pri->pvts[chanpos]);
#if defined(HAVE_PRI_CALL_REROUTING)
sig_pri_handle_subcmds(pri, chanpos, e->e, e->facility.channel,
e->facility.subcmds, e->facility.subcall);
#else
sig_pri_handle_subcmds(pri, chanpos, e->e, e->facility.channel,
e->facility.subcmds, e->facility.call);
#endif /* !defined(HAVE_PRI_CALL_REROUTING) */
sig_pri_unlock_private(pri->pvts[chanpos]);
}
}
break;
case PRI_EVENT_ANSWER:
if (sig_pri_is_cis_call(e->answer.channel)) {
#if defined(HAVE_PRI_CALL_WAITING)
/* Call is CIS so do normal CONNECT_ACKNOWLEDGE. */
pri_connect_ack(pri->pri, e->answer.call, 0);
#endif /* defined(HAVE_PRI_CALL_WAITING) */
sig_pri_handle_cis_subcmds(pri, e->e, e->answer.subcmds,
e->answer.call);
break;
}
chanpos = pri_find_principle(pri, e->answer.channel, e->answer.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Answer on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
break;
}
chanpos = pri_fixup_principle(pri, chanpos, e->answer.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Answer requested on channel %d/%d not in use on span %d\n",
PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
break;
}
#if defined(HAVE_PRI_CALL_WAITING)
if (pri->pvts[chanpos]->is_call_waiting) {
if (pri->pvts[chanpos]->no_b_channel) {
int new_chanpos;
/*
* Need to find a free channel now or
* kill the call with PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION.
*/
new_chanpos = pri_find_empty_chan(pri, 1);
if (new_chanpos < 0) {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->answer.channel,
e->answer.subcmds, e->answer.call);
sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCBS);
if (pri->pvts[chanpos]->owner) {
pri->pvts[chanpos]->owner->hangupcause = PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION;
switch (pri->pvts[chanpos]->owner->_state) {
case AST_STATE_BUSY:
case AST_STATE_UP:
ast_softhangup_nolock(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
break;
default:
pri_queue_control(pri, chanpos, AST_CONTROL_CONGESTION);
break;
}
} else {
pri->pvts[chanpos]->is_call_waiting = 0;
ast_atomic_fetchadd_int(&pri->num_call_waiting_calls, -1);
pri_hangup(pri->pri, e->answer.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
pri->pvts[chanpos]->call = NULL;
}
sig_pri_unlock_private(pri->pvts[chanpos]);
break;
}
chanpos = pri_fixup_principle(pri, new_chanpos, e->answer.call);
if (chanpos < 0) {
ast_log(LOG_WARNING,
"Unable to move call waiting call channel on span %d\n",
pri->span);
break;
}
}
pri_connect_ack(pri->pri, e->answer.call, PVT_TO_CHANNEL(pri->pvts[chanpos]));
} else {
/* Call is normal so do normal CONNECT_ACKNOWLEDGE. */
pri_connect_ack(pri->pri, e->answer.call, 0);
}
#endif /* defined(HAVE_PRI_CALL_WAITING) */
sig_pri_lock_private(pri->pvts[chanpos]);
#if defined(HAVE_PRI_CALL_WAITING)
if (pri->pvts[chanpos]->is_call_waiting) {
pri->pvts[chanpos]->is_call_waiting = 0;
ast_atomic_fetchadd_int(&pri->num_call_waiting_calls, -1);
sig_pri_span_devstate_changed(pri);
}
#endif /* defined(HAVE_PRI_CALL_WAITING) */
sig_pri_handle_subcmds(pri, chanpos, e->e, e->answer.channel,
e->answer.subcmds, e->answer.call);
pri->pvts[chanpos]->proceeding = 1;
sig_pri_open_media(pri->pvts[chanpos]);
pri_queue_control(pri, chanpos, AST_CONTROL_ANSWER);
/* Enable echo cancellation if it's not on already */
sig_pri_set_dialing(pri->pvts[chanpos], 0);
sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
#ifdef SUPPORT_USERUSER
if (!ast_strlen_zero(e->answer.useruserinfo)) {
struct ast_channel *owner;
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
pbx_builtin_setvar_helper(owner, "USERUSERINFO",
e->answer.useruserinfo);
ast_channel_unlock(owner);
}
}
#endif
sig_pri_unlock_private(pri->pvts[chanpos]);
break;
#if defined(HAVE_PRI_CALL_WAITING)
case PRI_EVENT_CONNECT_ACK:
if (sig_pri_is_cis_call(e->connect_ack.channel)) {
sig_pri_handle_cis_subcmds(pri, e->e, e->connect_ack.subcmds,
e->connect_ack.call);
break;
}
chanpos = pri_find_principle(pri, e->connect_ack.channel,
e->connect_ack.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Connect ACK on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->connect_ack.channel),
PRI_CHANNEL(e->connect_ack.channel), pri->span);
break;
}
chanpos = pri_fixup_principle(pri, chanpos, e->connect_ack.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Connect ACK requested on channel %d/%d not in use on span %d\n",
PRI_SPAN(e->connect_ack.channel),
PRI_CHANNEL(e->connect_ack.channel), pri->span);
break;
}
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_span_devstate_changed(pri);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->connect_ack.channel,
e->connect_ack.subcmds, e->connect_ack.call);
sig_pri_open_media(pri->pvts[chanpos]);
sig_pri_unlock_private(pri->pvts[chanpos]);
break;
#endif /* defined(HAVE_PRI_CALL_WAITING) */
case PRI_EVENT_HANGUP:
if (sig_pri_is_cis_call(e->hangup.channel)) {
sig_pri_handle_cis_subcmds(pri, e->e, e->hangup.subcmds,
e->hangup.call);
pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
break;
}
chanpos = pri_find_principle(pri, e->hangup.channel, e->hangup.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Hangup requested on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
/*
* Continue hanging up the call even though
* it is on an unconfigured channel.
*/
pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
} else {
chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->hangup.channel,
e->hangup.subcmds, e->hangup.call);
if (!pri->pvts[chanpos]->alreadyhungup) {
/* we're calling here dahdi_hangup so once we get there we need to clear p->call after calling pri_hangup */
pri->pvts[chanpos]->alreadyhungup = 1;
switch (e->hangup.cause) {
case PRI_CAUSE_USER_BUSY:
case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCBS);
break;
default:
break;
}
if (pri->pvts[chanpos]->owner) {
int do_hangup = 0;
/* Queue a BUSY instead of a hangup if our cause is appropriate */
pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
switch (pri->pvts[chanpos]->owner->_state) {
case AST_STATE_BUSY:
case AST_STATE_UP:
do_hangup = 1;
break;
default:
if (!pri->pvts[chanpos]->outgoing) {
/*
* The incoming call leg hung up before getting
* connected so just hangup the call.
*/
do_hangup = 1;
break;
}
switch (e->hangup.cause) {
case PRI_CAUSE_USER_BUSY:
pri_queue_control(pri, chanpos, AST_CONTROL_BUSY);
break;
case PRI_CAUSE_CALL_REJECTED:
case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
case PRI_CAUSE_SWITCH_CONGESTION:
case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
pri_queue_control(pri, chanpos, AST_CONTROL_CONGESTION);
break;
default:
do_hangup = 1;
break;
}
break;
}
if (do_hangup) {
#if defined(HAVE_PRI_AOC_EVENTS)
if (detect_aoc_e_subcmd(e->hangup.subcmds)) {
/* If a AOC-E msg was sent during the release, we must use a
* AST_CONTROL_HANGUP frame to guarantee that frame gets read before hangup */
pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
} else {
pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
}
#else
pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
}
} else {
/*
* Continue hanging up the call even though
* we do not have an owner.
*/
pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
pri->pvts[chanpos]->call = NULL;
}
ast_verb(3, "Channel %d/%d, span %d got hangup, cause %d\n",
pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, e->hangup.cause);
} else {
/* Continue hanging up the call. */
pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
pri->pvts[chanpos]->call = NULL;
}
if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
ast_verb(3, "Forcing restart of channel %d/%d on span %d since channel reported in use\n",
PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
pri->pvts[chanpos]->resetting = 1;
}
if (e->hangup.aoc_units > -1)
ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
#ifdef SUPPORT_USERUSER
if (!ast_strlen_zero(e->hangup.useruserinfo)) {
struct ast_channel *owner;
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
pbx_builtin_setvar_helper(owner, "USERUSERINFO",
e->hangup.useruserinfo);
ast_channel_unlock(owner);
}
}
#endif
sig_pri_unlock_private(pri->pvts[chanpos]);
} else {
/*
* Continue hanging up the call even though
* we do not remember it (if we ever did).
*/
pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
}
}
break;
case PRI_EVENT_HANGUP_REQ:
if (sig_pri_is_cis_call(e->hangup.channel)) {
sig_pri_handle_cis_subcmds(pri, e->e, e->hangup.subcmds,
e->hangup.call);
pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
break;
}
chanpos = pri_find_principle(pri, e->hangup.channel, e->hangup.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
/*
* Continue hanging up the call even though
* it is on an unconfigured channel.
*/
pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
} else {
chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->hangup.channel,
e->hangup.subcmds, e->hangup.call);
#if defined(HAVE_PRI_CALL_HOLD)
if (e->hangup.call_active && e->hangup.call_held
&& pri->hold_disconnect_transfer) {
/* We are to transfer the call instead of simply hanging up. */
sig_pri_unlock_private(pri->pvts[chanpos]);
if (!sig_pri_attempt_transfer(pri, e->hangup.call_held, 1,
e->hangup.call_active, 0, NULL, NULL)) {
break;
}
sig_pri_lock_private(pri->pvts[chanpos]);
}
#endif /* defined(HAVE_PRI_CALL_HOLD) */
switch (e->hangup.cause) {
case PRI_CAUSE_USER_BUSY:
case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCBS);
break;
default:
break;
}
if (pri->pvts[chanpos]->owner) {
int do_hangup = 0;
pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
switch (pri->pvts[chanpos]->owner->_state) {
case AST_STATE_BUSY:
case AST_STATE_UP:
do_hangup = 1;
break;
default:
if (!pri->pvts[chanpos]->outgoing) {
/*
* The incoming call leg hung up before getting
* connected so just hangup the call.
*/
do_hangup = 1;
break;
}
switch (e->hangup.cause) {
case PRI_CAUSE_USER_BUSY:
pri_queue_control(pri, chanpos, AST_CONTROL_BUSY);
break;
case PRI_CAUSE_CALL_REJECTED:
case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
case PRI_CAUSE_SWITCH_CONGESTION:
case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
pri_queue_control(pri, chanpos, AST_CONTROL_CONGESTION);
break;
default:
do_hangup = 1;
break;
}
break;
}
if (do_hangup) {
#if defined(HAVE_PRI_AOC_EVENTS)
if (!pri->pvts[chanpos]->holding_aoce
&& pri->aoce_delayhangup
&& ast_bridged_channel(pri->pvts[chanpos]->owner)) {
sig_pri_send_aoce_termination_request(pri, chanpos,
pri_get_timer(pri->pri, PRI_TIMER_T305) / 2);
} else if (detect_aoc_e_subcmd(e->hangup.subcmds)) {
/* If a AOC-E msg was sent during the Disconnect, we must use a AST_CONTROL_HANGUP frame
* to guarantee that frame gets read before hangup */
pri_queue_control(pri, chanpos, AST_CONTROL_HANGUP);
} else {
pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
}
#else
pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
}
ast_verb(3, "Channel %d/%d, span %d got hangup request, cause %d\n",
PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span, e->hangup.cause);
} else {
/*
* Continue hanging up the call even though
* we do not have an owner.
*/
pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
pri->pvts[chanpos]->call = NULL;
}
if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
ast_verb(3, "Forcing restart of channel %d/%d span %d since channel reported in use\n",
PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
pri->pvts[chanpos]->resetting = 1;
}
#ifdef SUPPORT_USERUSER
if (!ast_strlen_zero(e->hangup.useruserinfo)) {
struct ast_channel *owner;
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
pbx_builtin_setvar_helper(owner, "USERUSERINFO",
e->hangup.useruserinfo);
ast_channel_unlock(owner);
}
}
#endif
sig_pri_unlock_private(pri->pvts[chanpos]);
} else {
/*
* Continue hanging up the call even though
* we do not remember it (if we ever did).
*/
pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
}
}
break;
case PRI_EVENT_HANGUP_ACK:
if (sig_pri_is_cis_call(e->hangup.channel)) {
sig_pri_handle_cis_subcmds(pri, e->e, e->hangup.subcmds,
e->hangup.call);
break;
}
chanpos = pri_find_principle(pri, e->hangup.channel, e->hangup.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Hangup ACK requested on unconfigured channel number %d/%d span %d\n",
PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
} else {
chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
pri->pvts[chanpos]->call = NULL;
pri->pvts[chanpos]->resetting = 0;
if (pri->pvts[chanpos]->owner) {
ast_verb(3, "Channel %d/%d, span %d got hangup ACK\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
}
#ifdef SUPPORT_USERUSER
if (!ast_strlen_zero(e->hangup.useruserinfo)) {
struct ast_channel *owner;
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
pbx_builtin_setvar_helper(owner, "USERUSERINFO",
e->hangup.useruserinfo);
ast_channel_unlock(owner);
}
}
#endif
sig_pri_unlock_private(pri->pvts[chanpos]);
}
}
break;
case PRI_EVENT_CONFIG_ERR:
ast_log(LOG_WARNING, "PRI Error on span %d: %s\n", pri->span, e->err.err);
break;
case PRI_EVENT_RESTART_ACK:
chanpos = pri_find_principle(pri, e->restartack.channel, NULL);
if (chanpos < 0) {
/* Sometime switches (e.g. I421 / British Telecom) don't give us the
channel number, so we have to figure it out... This must be why
everybody resets exactly a channel at a time. */
for (x = 0; x < pri->numchans; x++) {
if (pri->pvts[x] && pri->pvts[x]->resetting) {
chanpos = x;
sig_pri_lock_private(pri->pvts[chanpos]);
ast_debug(1, "Assuming restart ack is really for channel %d/%d span %d\n", pri->pvts[chanpos]->logicalspan,
pri->pvts[chanpos]->prioffset, pri->span);
if (pri->pvts[chanpos]->owner) {
ast_log(LOG_WARNING, "Got restart ack on channel %d/%d with owner on span %d\n", pri->pvts[chanpos]->logicalspan,
pri->pvts[chanpos]->prioffset, pri->span);
pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
}
pri->pvts[chanpos]->resetting = 0;
ast_verb(3, "B-channel %d/%d successfully restarted on span %d\n", pri->pvts[chanpos]->logicalspan,
pri->pvts[chanpos]->prioffset, pri->span);
sig_pri_unlock_private(pri->pvts[chanpos]);
if (pri->resetting)
pri_check_restart(pri);
break;
}
}
if (chanpos < 0) {
ast_log(LOG_WARNING, "Restart ACK requested on strange channel %d/%d span %d\n",
PRI_SPAN(e->restartack.channel), PRI_CHANNEL(e->restartack.channel), pri->span);
}
} else {
if (pri->pvts[chanpos]) {
sig_pri_lock_private(pri->pvts[chanpos]);
if (pri->pvts[chanpos]->owner) {
ast_log(LOG_WARNING, "Got restart ack on channel %d/%d span %d with owner\n",
PRI_SPAN(e->restartack.channel), PRI_CHANNEL(e->restartack.channel), pri->span);
pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
}
pri->pvts[chanpos]->resetting = 0;
ast_verb(3, "B-channel %d/%d successfully restarted on span %d\n", pri->pvts[chanpos]->logicalspan,
pri->pvts[chanpos]->prioffset, pri->span);
sig_pri_unlock_private(pri->pvts[chanpos]);
if (pri->resetting)
pri_check_restart(pri);
}
}
break;
case PRI_EVENT_SETUP_ACK:
if (sig_pri_is_cis_call(e->setup_ack.channel)) {
sig_pri_handle_cis_subcmds(pri, e->e, e->setup_ack.subcmds,
e->setup_ack.call);
break;
}
chanpos = pri_find_principle(pri, e->setup_ack.channel, e->setup_ack.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Received SETUP_ACKNOWLEDGE on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->setup_ack.channel), PRI_CHANNEL(e->setup_ack.channel), pri->span);
} else {
chanpos = pri_fixup_principle(pri, chanpos, e->setup_ack.call);
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->setup_ack.channel,
e->setup_ack.subcmds, e->setup_ack.call);
pri->pvts[chanpos]->setup_ack = 1;
/* Send any queued digits */
for (x = 0;x < strlen(pri->pvts[chanpos]->dialdest); x++) {
ast_debug(1, "Sending pending digit '%c'\n", pri->pvts[chanpos]->dialdest[x]);
pri_information(pri->pri, pri->pvts[chanpos]->call,
pri->pvts[chanpos]->dialdest[x]);
}
sig_pri_unlock_private(pri->pvts[chanpos]);
} else
ast_log(LOG_WARNING, "Unable to move channel %d!\n", e->setup_ack.channel);
}
break;
case PRI_EVENT_NOTIFY:
if (sig_pri_is_cis_call(e->notify.channel)) {
#if defined(HAVE_PRI_CALL_HOLD)
sig_pri_handle_cis_subcmds(pri, e->e, e->notify.subcmds,
e->notify.call);
#else
sig_pri_handle_cis_subcmds(pri, e->e, e->notify.subcmds, NULL);
#endif /* !defined(HAVE_PRI_CALL_HOLD) */
break;
}
#if defined(HAVE_PRI_CALL_HOLD)
chanpos = pri_find_principle(pri, e->notify.channel, e->notify.call);
#else
chanpos = pri_find_principle(pri, e->notify.channel, NULL);
#endif /* !defined(HAVE_PRI_CALL_HOLD) */
if (chanpos < 0) {
ast_log(LOG_WARNING, "Received NOTIFY on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->notify.channel), PRI_CHANNEL(e->notify.channel), pri->span);
} else {
sig_pri_lock_private(pri->pvts[chanpos]);
#if defined(HAVE_PRI_CALL_HOLD)
sig_pri_handle_subcmds(pri, chanpos, e->e, e->notify.channel,
e->notify.subcmds, e->notify.call);
#else
sig_pri_handle_subcmds(pri, chanpos, e->e, e->notify.channel,
e->notify.subcmds, NULL);
#endif /* !defined(HAVE_PRI_CALL_HOLD) */
switch (e->notify.info) {
case PRI_NOTIFY_REMOTE_HOLD:
if (!pri->discardremoteholdretrieval) {
pri_queue_control(pri, chanpos, AST_CONTROL_HOLD);
}
break;
case PRI_NOTIFY_REMOTE_RETRIEVAL:
if (!pri->discardremoteholdretrieval) {
pri_queue_control(pri, chanpos, AST_CONTROL_UNHOLD);
}
break;
}
sig_pri_unlock_private(pri->pvts[chanpos]);
}
break;
#if defined(HAVE_PRI_CALL_HOLD)
case PRI_EVENT_HOLD:
/* We should not be getting any CIS calls with this message type. */
if (sig_pri_handle_hold(pri, e)) {
pri_hold_rej(pri->pri, e->hold.call,
PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED);
} else {
pri_hold_ack(pri->pri, e->hold.call);
}
break;
#endif /* defined(HAVE_PRI_CALL_HOLD) */
#if defined(HAVE_PRI_CALL_HOLD)
case PRI_EVENT_HOLD_ACK:
ast_debug(1, "Event: HOLD_ACK\n");
break;
#endif /* defined(HAVE_PRI_CALL_HOLD) */
#if defined(HAVE_PRI_CALL_HOLD)
case PRI_EVENT_HOLD_REJ:
ast_debug(1, "Event: HOLD_REJ\n");
break;
#endif /* defined(HAVE_PRI_CALL_HOLD) */
#if defined(HAVE_PRI_CALL_HOLD)
case PRI_EVENT_RETRIEVE:
/* We should not be getting any CIS calls with this message type. */
sig_pri_handle_retrieve(pri, e);
break;
#endif /* defined(HAVE_PRI_CALL_HOLD) */
#if defined(HAVE_PRI_CALL_HOLD)
case PRI_EVENT_RETRIEVE_ACK:
ast_debug(1, "Event: RETRIEVE_ACK\n");
break;
#endif /* defined(HAVE_PRI_CALL_HOLD) */
#if defined(HAVE_PRI_CALL_HOLD)
case PRI_EVENT_RETRIEVE_REJ:
ast_debug(1, "Event: RETRIEVE_REJ\n");
break;
#endif /* defined(HAVE_PRI_CALL_HOLD) */
default:
ast_debug(1, "Event: %d\n", e->e);
break;
}
}
ast_mutex_unlock(&pri->lock);
}
/* Never reached */
return NULL;
}
| void pri_event_alarm | ( | struct sig_pri_span * | pri, |
| int | index, | ||
| int | before_start_pri | ||
| ) |
Definition at line 1671 of file sig_pri.c.
References DCHAN_NOTINALARM, DCHAN_UP, sig_pri_span::dchanavail, and pri_find_dchan().
Referenced by my_handle_dchan_exception(), and prepare_pri().
{
pri->dchanavail[index] &= ~(DCHAN_NOTINALARM | DCHAN_UP);
if (!before_start_pri)
pri_find_dchan(pri);
}
| void pri_event_noalarm | ( | struct sig_pri_span * | pri, |
| int | index, | ||
| int | before_start_pri | ||
| ) |
Definition at line 1678 of file sig_pri.c.
References DCHAN_NOTINALARM, sig_pri_span::dchanavail, and sig_pri_span::dchans.
Referenced by my_handle_dchan_exception(), and prepare_pri().
{
pri->dchanavail[index] |= DCHAN_NOTINALARM;
if (!before_start_pri)
pri_restart(pri->dchans[index]);
}
| static int pri_find_dchan | ( | struct sig_pri_span * | pri | ) | [static] |
Definition at line 966 of file sig_pri.c.
References ast_log(), DCHAN_AVAILABLE, sig_pri_span::dchanavail, sig_pri_span::dchans, sig_pri_span::fds, LOG_NOTICE, LOG_WARNING, sig_pri_span::no_d_channels, sig_pri_span::pri, sig_pri_span::sig, SIG_BRI_PTMP, SIG_PRI_NUM_DCHANS, and sig_pri_span::span.
Referenced by pri_dchannel(), and pri_event_alarm().
{
int oldslot = -1;
struct pri *old;
int newslot = -1;
int x;
old = pri->pri;
for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
if ((pri->dchanavail[x] == DCHAN_AVAILABLE) && (newslot < 0))
newslot = x;
if (pri->dchans[x] == old) {
oldslot = x;
}
}
if (newslot < 0) {
newslot = 0;
/* This is annoying to see on non persistent layer 2 connections. Let's not complain in that case */
if (pri->sig != SIG_BRI_PTMP && !pri->no_d_channels) {
pri->no_d_channels = 1;
ast_log(LOG_WARNING,
"Span %d: No D-channels available! Using Primary channel as D-channel anyway!\n",
pri->span);
}
} else {
pri->no_d_channels = 0;
}
if (old && (oldslot != newslot))
ast_log(LOG_NOTICE, "Switching from d-channel fd %d to fd %d!\n",
pri->fds[oldslot], pri->fds[newslot]);
pri->pri = pri->dchans[newslot];
return 0;
}
| static int pri_find_empty_chan | ( | struct sig_pri_span * | pri, |
| int | backwards | ||
| ) | [static] |
Definition at line 1421 of file sig_pri.c.
References ast_debug, sig_pri_chan::inalarm, sig_pri_chan::logicalspan, sig_pri_chan::no_b_channel, sig_pri_span::numchans, sig_pri_chan::owner, sig_pri_chan::prioffset, and sig_pri_span::pvts.
Referenced by pri_dchannel(), and sig_pri_handle_retrieve().
{
int x;
if (backwards)
x = pri->numchans;
else
x = 0;
for (;;) {
if (backwards && (x < 0))
break;
if (!backwards && (x >= pri->numchans))
break;
if (pri->pvts[x]
&& !pri->pvts[x]->no_b_channel
&& !pri->pvts[x]->inalarm
&& !pri->pvts[x]->owner) {
ast_debug(1, "Found empty available channel %d/%d\n",
pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
return x;
}
if (backwards)
x--;
else
x++;
}
return -1;
}
| static int pri_find_empty_nobch | ( | struct sig_pri_span * | pri | ) | [static] |
Definition at line 1462 of file sig_pri.c.
References ast_debug, sig_pri_span::calls, sig_pri_chan::inalarm, sig_pri_callback::new_nobch_intf, sig_pri_chan::no_b_channel, sig_pri_span::numchans, sig_pri_chan::owner, and sig_pri_span::pvts.
Referenced by pri_dchannel(), sig_pri_cw_available(), and sig_pri_handle_hold().
{
int idx;
for (idx = 0; idx < pri->numchans; ++idx) {
if (pri->pvts[idx]
&& pri->pvts[idx]->no_b_channel
&& !pri->pvts[idx]->inalarm
&& !pri->pvts[idx]->owner) {
ast_debug(1, "Found empty available no B channel interface\n");
return idx;
}
}
/* Need to create a new interface. */
if (pri->calls->new_nobch_intf) {
idx = pri->calls->new_nobch_intf(pri);
} else {
idx = -1;
}
return idx;
}
| static int pri_find_pri_call | ( | struct sig_pri_span * | pri, |
| q931_call * | call | ||
| ) | [static] |
Definition at line 1500 of file sig_pri.c.
References sig_pri_chan::call, sig_pri_span::numchans, and sig_pri_span::pvts.
Referenced by sig_pri_attempt_transfer().
| static int pri_find_principle | ( | struct sig_pri_span * | pri, |
| int | channel, | ||
| q931_call * | call | ||
| ) | [static] |
Definition at line 1093 of file sig_pri.c.
References sig_pri_chan::call, sig_pri_span::dchan_logical_span, sig_pri_chan::logicalspan, sig_pri_chan::no_b_channel, sig_pri_span::numchans, pri_active_dchan_index(), PRI_CHANNEL, PRI_EXPLICIT, PRI_HELD_CALL, PRI_SPAN, sig_pri_chan::prioffset, and sig_pri_span::pvts.
Referenced by pri_dchannel(), sig_pri_handle_hold(), and sig_pri_handle_retrieve().
{
int x;
int span;
int principle;
int prioffset;
if (channel < 0) {
/* Channel is not picked yet. */
return -1;
}
prioffset = PRI_CHANNEL(channel);
if (!prioffset || (channel & PRI_HELD_CALL)) {
if (!call) {
/* Cannot find a call waiting call or held call without a call. */
return -1;
}
principle = -1;
for (x = 0; x < pri->numchans; ++x) {
if (pri->pvts[x]
&& pri->pvts[x]->call == call) {
principle = x;
break;
}
}
return principle;
}
span = PRI_SPAN(channel);
if (!(channel & PRI_EXPLICIT)) {
int index;
index = pri_active_dchan_index(pri);
if (index == -1) {
return -1;
}
span = pri->dchan_logical_span[index];
}
principle = -1;
for (x = 0; x < pri->numchans; x++) {
if (pri->pvts[x]
&& pri->pvts[x]->prioffset == prioffset
&& pri->pvts[x]->logicalspan == span
&& !pri->pvts[x]->no_b_channel) {
principle = x;
break;
}
}
return principle;
}
| static int pri_fixup_principle | ( | struct sig_pri_span * | pri, |
| int | principle, | ||
| q931_call * | call | ||
| ) | [static] |
Definition at line 1160 of file sig_pri.c.
References sig_pri_chan::alerting, sig_pri_chan::alreadyhungup, sig_pri_chan::aoc_e, sig_pri_chan::aoc_s_request_invoke_id, sig_pri_chan::aoc_s_request_invoke_id_valid, ast_channel_unlock, ast_log(), ast_verb, sig_pri_chan::call, sig_pri_chan::channel, sig_pri_chan::context, sig_pri_chan::digital, sig_pri_chan::hidecallerid, sig_pri_chan::hidecalleridname, sig_pri_chan::holding_aoce, sig_pri_chan::immediate, sig_pri_chan::is_call_waiting, sig_pri_chan::isidlecall, sig_pri_chan::keypad_digits, LOG_WARNING, sig_pri_chan::logicalspan, sig_pri_chan::mastertrunkgroup, sig_pri_chan::mohinterpret, ast_channel::name, sig_pri_chan::no_b_channel, sig_pri_span::numchans, sig_pri_chan::outgoing, sig_pri_chan::owner, sig_pri_chan::priexclusive, sig_pri_chan::priindication_oob, sig_pri_chan::proceeding, sig_pri_chan::progress, sig_pri_span::pvts, sig_pri_chan::reverse_charging_indication, sig_pri_chan::setup_ack, sig_pri_fixup_chans(), sig_pri_lock_owner(), sig_pri_lock_private(), sig_pri_open_media(), sig_pri_unlock_private(), sig_pri_chan::stripmsd, sig_pri_chan::use_callerid, sig_pri_chan::use_callingpres, sig_pri_chan::user_tag, and sig_pri_chan::waiting_for_aoce.
Referenced by pri_dchannel(), sig_pri_handle_hold(), and sig_pri_handle_retrieve().
{
int x;
if (principle < 0 || pri->numchans <= principle) {
/* Out of rannge */
return -1;
}
if (!call) {
/* No call */
return principle;
}
if (pri->pvts[principle] && pri->pvts[principle]->call == call) {
/* Call is already on the specified principle. */
return principle;
}
/* Find the old principle location. */
for (x = 0; x < pri->numchans; x++) {
struct sig_pri_chan *new_chan;
struct sig_pri_chan *old_chan;
if (!pri->pvts[x] || pri->pvts[x]->call != call) {
continue;
}
/* Found our call */
new_chan = pri->pvts[principle];
old_chan = pri->pvts[x];
/* Get locks to safely move to the new private structure. */
sig_pri_lock_private(old_chan);
sig_pri_lock_owner(pri, x);
sig_pri_lock_private(new_chan);
ast_verb(3, "Moving call (%s) from channel %d to %d.\n",
old_chan->owner ? old_chan->owner->name : "",
old_chan->channel, new_chan->channel);
if (new_chan->owner) {
ast_log(LOG_WARNING,
"Can't move call (%s) from channel %d to %d. It is already in use.\n",
old_chan->owner ? old_chan->owner->name : "",
old_chan->channel, new_chan->channel);
sig_pri_unlock_private(new_chan);
if (old_chan->owner) {
ast_channel_unlock(old_chan->owner);
}
sig_pri_unlock_private(old_chan);
return -1;
}
sig_pri_fixup_chans(old_chan, new_chan);
/* Fix it all up now */
new_chan->owner = old_chan->owner;
old_chan->owner = NULL;
new_chan->call = old_chan->call;
old_chan->call = NULL;
/* Transfer flags from the old channel. */
#if defined(HAVE_PRI_AOC_EVENTS)
new_chan->aoc_s_request_invoke_id_valid = old_chan->aoc_s_request_invoke_id_valid;
new_chan->waiting_for_aoce = old_chan->waiting_for_aoce;
new_chan->holding_aoce = old_chan->holding_aoce;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
new_chan->alerting = old_chan->alerting;
new_chan->alreadyhungup = old_chan->alreadyhungup;
new_chan->isidlecall = old_chan->isidlecall;
new_chan->proceeding = old_chan->proceeding;
new_chan->progress = old_chan->progress;
new_chan->setup_ack = old_chan->setup_ack;
new_chan->outgoing = old_chan->outgoing;
new_chan->digital = old_chan->digital;
#if defined(HAVE_PRI_CALL_WAITING)
new_chan->is_call_waiting = old_chan->is_call_waiting;
#endif /* defined(HAVE_PRI_CALL_WAITING) */
#if defined(HAVE_PRI_AOC_EVENTS)
old_chan->aoc_s_request_invoke_id_valid = 0;
old_chan->waiting_for_aoce = 0;
old_chan->holding_aoce = 0;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
old_chan->alerting = 0;
old_chan->alreadyhungup = 0;
old_chan->isidlecall = 0;
old_chan->proceeding = 0;
old_chan->progress = 0;
old_chan->setup_ack = 0;
old_chan->outgoing = 0;
old_chan->digital = 0;
#if defined(HAVE_PRI_CALL_WAITING)
old_chan->is_call_waiting = 0;
#endif /* defined(HAVE_PRI_CALL_WAITING) */
/* More stuff to transfer to the new channel. */
#if defined(HAVE_PRI_REVERSE_CHARGE)
new_chan->reverse_charging_indication = old_chan->reverse_charging_indication;
#endif /* defined(HAVE_PRI_REVERSE_CHARGE) */
#if defined(HAVE_PRI_SETUP_KEYPAD)
strcpy(new_chan->keypad_digits, old_chan->keypad_digits);
#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
#if defined(HAVE_PRI_AOC_EVENTS)
new_chan->aoc_s_request_invoke_id = old_chan->aoc_s_request_invoke_id;
new_chan->aoc_e = old_chan->aoc_e;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
strcpy(new_chan->user_tag, old_chan->user_tag);
if (new_chan->no_b_channel) {
/* Copy the real channel configuration to the no B channel interface. */
new_chan->hidecallerid = old_chan->hidecallerid;
new_chan->hidecalleridname = old_chan->hidecalleridname;
new_chan->immediate = old_chan->immediate;
new_chan->priexclusive = old_chan->priexclusive;
new_chan->priindication_oob = old_chan->priindication_oob;
new_chan->use_callerid = old_chan->use_callerid;
new_chan->use_callingpres = old_chan->use_callingpres;
new_chan->stripmsd = old_chan->stripmsd;
strcpy(new_chan->context, old_chan->context);
strcpy(new_chan->mohinterpret, old_chan->mohinterpret);
/* Become a member of the old channel span/trunk-group. */
new_chan->logicalspan = old_chan->logicalspan;
new_chan->mastertrunkgroup = old_chan->mastertrunkgroup;
} else if (old_chan->no_b_channel) {
/*
* We are transitioning from a held/call-waiting channel to a
* real channel so we need to make sure that the media path is
* open. (Needed especially if the channel is natively
* bridged.)
*/
sig_pri_open_media(new_chan);
}
sig_pri_unlock_private(old_chan);
if (new_chan->owner) {
ast_channel_unlock(new_chan->owner);
}
sig_pri_unlock_private(new_chan);
return principle;
}
ast_verb(3, "Call specified, but not found.\n");
return -1;
}
| static int pri_grab | ( | struct sig_pri_chan * | p, |
| struct sig_pri_span * | pri | ||
| ) | [inline, static] |
Definition at line 283 of file sig_pri.c.
References ast_mutex_trylock, sig_pri_span::lock, sig_pri_span::master, and PRI_DEADLOCK_AVOIDANCE.
Referenced by pri_send_callrerouting_facility_exec(), pri_send_keypad_facility_exec(), pri_ss_thread(), sig_pri_answer(), sig_pri_call(), sig_pri_chan_alarm_notify(), sig_pri_digit_begin(), sig_pri_hangup(), and sig_pri_indicate().
{
int res;
/* Grab the lock first */
do {
res = ast_mutex_trylock(&pri->lock);
if (res) {
PRI_DEADLOCK_AVOIDANCE(p);
}
} while (res);
/* Then break the poll */
pthread_kill(pri->master, SIGURG);
return 0;
}
| int pri_is_up | ( | struct sig_pri_span * | pri | ) |
Definition at line 926 of file sig_pri.c.
References DCHAN_AVAILABLE, sig_pri_span::dchanavail, and SIG_PRI_NUM_DCHANS.
Referenced by pri_dchannel().
{
int x;
for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
if (pri->dchanavail[x] == DCHAN_AVAILABLE)
return 1;
}
return 0;
}
| int pri_maintenance_bservice | ( | struct pri * | pri, |
| struct sig_pri_chan * | p, | ||
| int | changestatus | ||
| ) |
Definition at line 7358 of file sig_pri.c.
References sig_pri_chan::channel, PRI_SPAN, and PVT_TO_CHANNEL().
Referenced by handle_pri_service_generic().
{
int channel = PVT_TO_CHANNEL(p);
int span = PRI_SPAN(channel);
return pri_maintenance_service(pri, span, channel, changestatus);
}
| static char* pri_order | ( | int | level | ) | [static] |
Definition at line 936 of file sig_pri.c.
Referenced by pri_dchannel(), and sig_pri_cli_show_span().
{
switch (level) {
case 0:
return "Primary";
case 1:
return "Secondary";
case 2:
return "Tertiary";
case 3:
return "Quaternary";
default:
return "<Unknown>";
}
}
| static void pri_queue_control | ( | struct sig_pri_span * | pri, |
| int | chanpos, | ||
| int | subclass | ||
| ) | [static] |
Definition at line 1067 of file sig_pri.c.
References AST_FRAME_CONTROL, sig_pri_chan::calls, sig_pri_chan::chan_pvt, ast_frame_subclass::integer, pri_queue_frame(), sig_pri_span::pvts, sig_pri_callback::queue_control, and ast_frame::subclass.
Referenced by pri_dchannel(), and sig_pri_handle_retrieve().
{
struct ast_frame f = {AST_FRAME_CONTROL, };
struct sig_pri_chan *p = pri->pvts[chanpos];
if (p->calls->queue_control) {
p->calls->queue_control(p->chan_pvt, subclass);
}
f.subclass.integer = subclass;
pri_queue_frame(pri, chanpos, &f);
}
| static void pri_queue_frame | ( | struct sig_pri_span * | pri, |
| int | chanpos, | ||
| struct ast_frame * | frame | ||
| ) | [static] |
Definition at line 1044 of file sig_pri.c.
References ast_channel_unlock, ast_queue_frame(), sig_pri_chan::owner, sig_pri_span::pvts, and sig_pri_lock_owner().
Referenced by pri_dchannel(), and pri_queue_control().
{
sig_pri_lock_owner(pri, chanpos);
if (pri->pvts[chanpos]->owner) {
ast_queue_frame(pri->pvts[chanpos]->owner, frame);
ast_channel_unlock(pri->pvts[chanpos]->owner);
}
}
| static void pri_rel | ( | struct sig_pri_span * | pri | ) | [inline, static] |
Definition at line 112 of file sig_pri.c.
References ast_mutex_unlock, and sig_pri_span::lock.
Referenced by pri_send_callrerouting_facility_exec(), pri_send_keypad_facility_exec(), pri_ss_thread(), sig_pri_answer(), sig_pri_call(), sig_pri_chan_alarm_notify(), sig_pri_digit_begin(), sig_pri_hangup(), and sig_pri_indicate().
{
ast_mutex_unlock(&pri->lock);
}
| int pri_send_callrerouting_facility_exec | ( | struct sig_pri_chan * | p, |
| enum ast_channel_state | chanstate, | ||
| const char * | destination, | ||
| const char * | original, | ||
| const char * | reason | ||
| ) |
Definition at line 7333 of file sig_pri.c.
References ast_log(), sig_pri_chan::call, LOG_DEBUG, sig_pri_span::pri, sig_pri_chan::pri, pri_grab(), pri_rel(), sig_pri_lock_private(), sig_pri_unlock_private(), and sig_pri_span::span.
Referenced by dahdi_send_callrerouting_facility_exec().
{
int res = -1;
sig_pri_lock_private(p);
if (!p->pri || !p->call) {
ast_log(LOG_DEBUG, "Unable to find pri or call on channel!\n");
sig_pri_unlock_private(p);
return -1;
}
if (!pri_grab(p, p->pri)) {
res = pri_callrerouting_facility(p->pri->pri, p->call, destination, original, reason);
pri_rel(p->pri);
} else {
ast_log(LOG_DEBUG, "Unable to grab pri to send callrerouting facility on span %d!\n", p->pri->span);
}
sig_pri_unlock_private(p);
return res;
}
| int pri_send_keypad_facility_exec | ( | struct sig_pri_chan * | p, |
| const char * | digits | ||
| ) |
Definition at line 7309 of file sig_pri.c.
References ast_debug, sig_pri_chan::call, sig_pri_span::pri, sig_pri_chan::pri, pri_grab(), pri_rel(), sig_pri_lock_private(), and sig_pri_unlock_private().
Referenced by dahdi_send_keypad_facility_exec().
{
sig_pri_lock_private(p);
if (!p->pri || !p->call) {
ast_debug(1, "Unable to find pri or call on channel!\n");
sig_pri_unlock_private(p);
return -1;
}
if (!pri_grab(p, p->pri)) {
pri_keypad_facility(p->pri->pri, p->call, digits);
pri_rel(p->pri);
} else {
ast_debug(1, "Unable to grab pri to send keypad facility!\n");
sig_pri_unlock_private(p);
return -1;
}
sig_pri_unlock_private(p);
return 0;
}
| static void* pri_ss_thread | ( | void * | data | ) | [static] |
Definition at line 1563 of file sig_pri.c.
References sig_pri_span::append_msn_to_user_tag, AST_CAUSE_UNALLOCATED, ast_copy_string(), ast_exists_extension(), ast_free, ast_hangup(), ast_ignore_pattern(), ast_log(), ast_matchmore_extension(), AST_MAX_EXTENSION, ast_pbx_run(), ast_setstate(), AST_STATE_RING, ast_strdup, ast_strlen_zero(), ast_verb, ast_waitfordigit(), sig_pri_chan::call, ast_channel::caller, sig_pri_chan::cid_num, ast_channel::context, DAHDI_OVERLAPDIAL_INCOMING, ast_channel::dialed, ast_channel::exten, sig_pri_chan::exten, exten, ast_channel::hangupcause, ast_party_caller::id, sig_pri_span::initial_user_tag, len(), LOG_DEBUG, LOG_WARNING, ast_channel::name, sig_pri_span::nodetype, ast_party_dialed::number, sig_pri_span::overlapdial, sig_pri_chan::owner, sig_pri_span::pri, sig_pri_chan::pri, pri_gendigittimeout, pri_grab(), pri_matchdigittimeout, pri_rel(), sig_pri_chan::proceeding, PVT_TO_CHANNEL(), sig_pri_dsp_reset_and_flush_digits(), sig_pri_lock_private(), sig_pri_play_tone(), sig_pri_set_echocanceller(), SIG_PRI_TONE_DIALTONE, sig_pri_unlock_private(), sig_pri_span::span, ast_party_dialed::str, ast_party_id::tag, ast_channel::tech_pvt, and sig_pri_chan::user_tag.
Referenced by pri_dchannel().
{
struct sig_pri_chan *p = data;
struct ast_channel *chan = p->owner;
char exten[AST_MAX_EXTENSION];
int res;
int len;
int timeout;
if (!chan) {
/* We lost the owner before we could get started. */
return NULL;
}
/*
* In the bizarre case where the channel has become a zombie before we
* even get started here, abort safely.
*/
if (!chan->tech_pvt) {
ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", chan->name);
ast_hangup(chan);
return NULL;
}
ast_verb(3, "Starting simple switch on '%s'\n", chan->name);
sig_pri_dsp_reset_and_flush_digits(p);
/* Now loop looking for an extension */
ast_copy_string(exten, p->exten, sizeof(exten));
len = strlen(exten);
res = 0;
while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
if (len && !ast_ignore_pattern(chan->context, exten))
sig_pri_play_tone(p, -1);
else
sig_pri_play_tone(p, SIG_PRI_TONE_DIALTONE);
if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num))
timeout = pri_matchdigittimeout;
else
timeout = pri_gendigittimeout;
res = ast_waitfordigit(chan, timeout);
if (res < 0) {
ast_log(LOG_DEBUG, "waitfordigit returned < 0...\n");
ast_hangup(chan);
return NULL;
} else if (res) {
exten[len++] = res;
exten[len] = '\0';
} else
break;
}
/* if no extension was received ('unspecified') on overlap call, use the 's' extension */
if (ast_strlen_zero(exten)) {
ast_verb(3, "Going to extension s|1 because of empty extension received on overlap call\n");
exten[0] = 's';
exten[1] = '\0';
} else {
ast_free(chan->dialed.number.str);
chan->dialed.number.str = ast_strdup(exten);
if (p->pri->append_msn_to_user_tag && p->pri->nodetype != PRI_NETWORK) {
/*
* Update the user tag for party id's from this device for this call
* now that we have a complete MSN from the network.
*/
snprintf(p->user_tag, sizeof(p->user_tag), "%s_%s", p->pri->initial_user_tag,
exten);
ast_free(chan->caller.id.tag);
chan->caller.id.tag = ast_strdup(p->user_tag);
}
}
sig_pri_play_tone(p, -1);
if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num)) {
/* Start the real PBX */
ast_copy_string(chan->exten, exten, sizeof(chan->exten));
sig_pri_dsp_reset_and_flush_digits(p);
if (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) {
sig_pri_lock_private(p);
if (p->pri->pri) {
if (!pri_grab(p, p->pri)) {
pri_proceeding(p->pri->pri, p->call, PVT_TO_CHANNEL(p), 0);
p->proceeding = 1;
pri_rel(p->pri);
} else {
ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->pri->span);
}
}
sig_pri_unlock_private(p);
}
sig_pri_set_echocanceller(p, 1);
ast_setstate(chan, AST_STATE_RING);
res = ast_pbx_run(chan);
if (res) {
ast_log(LOG_WARNING, "PBX exited non-zero!\n");
}
} else {
ast_log(LOG_DEBUG, "No such possible extension '%s' in context '%s'\n", exten, chan->context);
chan->hangupcause = AST_CAUSE_UNALLOCATED;
ast_hangup(chan);
p->exten[0] = '\0';
/* Since we send release complete here, we won't get one */
p->call = NULL;
}
return NULL;
}
| static enum AST_PARTY_CHAR_SET pri_to_ast_char_set | ( | int | pri_char_set | ) | [static] |
Definition at line 475 of file sig_pri.c.
References AST_PARTY_CHAR_SET_ISO10646_BMPSTRING, AST_PARTY_CHAR_SET_ISO10646_UTF_8STRING, AST_PARTY_CHAR_SET_ISO8859_1, AST_PARTY_CHAR_SET_ISO8859_2, AST_PARTY_CHAR_SET_ISO8859_3, AST_PARTY_CHAR_SET_ISO8859_4, AST_PARTY_CHAR_SET_ISO8859_5, AST_PARTY_CHAR_SET_ISO8859_7, AST_PARTY_CHAR_SET_UNKNOWN, and AST_PARTY_CHAR_SET_WITHDRAWN.
Referenced by sig_pri_party_name_convert().
{
enum AST_PARTY_CHAR_SET ast_char_set;
switch (pri_char_set) {
default:
case PRI_CHAR_SET_UNKNOWN:
ast_char_set = AST_PARTY_CHAR_SET_UNKNOWN;
break;
case PRI_CHAR_SET_ISO8859_1:
ast_char_set = AST_PARTY_CHAR_SET_ISO8859_1;
break;
case PRI_CHAR_SET_WITHDRAWN:
ast_char_set = AST_PARTY_CHAR_SET_WITHDRAWN;
break;
case PRI_CHAR_SET_ISO8859_2:
ast_char_set = AST_PARTY_CHAR_SET_ISO8859_2;
break;
case PRI_CHAR_SET_ISO8859_3:
ast_char_set = AST_PARTY_CHAR_SET_ISO8859_3;
break;
case PRI_CHAR_SET_ISO8859_4:
ast_char_set = AST_PARTY_CHAR_SET_ISO8859_4;
break;
case PRI_CHAR_SET_ISO8859_5:
ast_char_set = AST_PARTY_CHAR_SET_ISO8859_5;
break;
case PRI_CHAR_SET_ISO8859_7:
ast_char_set = AST_PARTY_CHAR_SET_ISO8859_7;
break;
case PRI_CHAR_SET_ISO10646_BMPSTRING:
ast_char_set = AST_PARTY_CHAR_SET_ISO10646_BMPSTRING;
break;
case PRI_CHAR_SET_ISO10646_UTF_8STRING:
ast_char_set = AST_PARTY_CHAR_SET_ISO10646_UTF_8STRING;
break;
}
return ast_char_set;
}
| static int pri_to_ast_presentation | ( | int | pri_presentation | ) | [static] |
Definition at line 377 of file sig_pri.c.
References AST_PRES_ALLOWED_NETWORK_NUMBER, AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, AST_PRES_NUMBER_NOT_AVAILABLE, AST_PRES_PROHIB_NETWORK_NUMBER, AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED, and AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN.
Referenced by sig_pri_party_name_convert(), and sig_pri_party_number_convert().
{
int ast_presentation;
switch (pri_presentation) {
case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
ast_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
break;
case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
ast_presentation = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
break;
case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
ast_presentation = AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN;
break;
case PRES_ALLOWED_NETWORK_NUMBER:
ast_presentation = AST_PRES_ALLOWED_NETWORK_NUMBER;
break;
case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
ast_presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
break;
case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
ast_presentation = AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
break;
case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
ast_presentation = AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN;
break;
case PRES_PROHIB_NETWORK_NUMBER:
ast_presentation = AST_PRES_PROHIB_NETWORK_NUMBER;
break;
case PRES_NUMBER_NOT_AVAILABLE:
ast_presentation = AST_PRES_NUMBER_NOT_AVAILABLE;
break;
default:
ast_presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
break;
}
return ast_presentation;
}
| static enum AST_REDIRECTING_REASON pri_to_ast_reason | ( | int | pri_reason | ) | [static] |
Definition at line 307 of file sig_pri.c.
References AST_REDIRECTING_REASON_DEFLECTION, AST_REDIRECTING_REASON_NO_ANSWER, AST_REDIRECTING_REASON_UNCONDITIONAL, AST_REDIRECTING_REASON_UNKNOWN, and AST_REDIRECTING_REASON_USER_BUSY.
Referenced by sig_pri_redirecting_convert().
{
enum AST_REDIRECTING_REASON ast_reason;
switch (pri_reason) {
case PRI_REDIR_FORWARD_ON_BUSY:
ast_reason = AST_REDIRECTING_REASON_USER_BUSY;
break;
case PRI_REDIR_FORWARD_ON_NO_REPLY:
ast_reason = AST_REDIRECTING_REASON_NO_ANSWER;
break;
case PRI_REDIR_DEFLECTION:
ast_reason = AST_REDIRECTING_REASON_DEFLECTION;
break;
case PRI_REDIR_UNCONDITIONAL:
ast_reason = AST_REDIRECTING_REASON_UNCONDITIONAL;
break;
case PRI_REDIR_UNKNOWN:
default:
ast_reason = AST_REDIRECTING_REASON_UNKNOWN;
break;
}
return ast_reason;
}
| static unsigned int PVT_TO_CHANNEL | ( | struct sig_pri_chan * | p | ) | [static] |
Definition at line 117 of file sig_pri.c.
References ast_debug, sig_pri_chan::logicalspan, sig_pri_chan::mastertrunkgroup, PRI_EXPLICIT, and sig_pri_chan::prioffset.
Referenced by pri_check_restart(), pri_dchannel(), pri_maintenance_bservice(), pri_ss_thread(), sig_pri_call(), sig_pri_handle_retrieve(), and sig_pri_indicate().
{
int res = (((p)->prioffset) | ((p)->logicalspan << 8) | (p->mastertrunkgroup ? PRI_EXPLICIT : 0));
ast_debug(5, "prioffset: %d mastertrunkgroup: %d logicalspan: %d result: %d\n",
p->prioffset, p->mastertrunkgroup, p->logicalspan, res);
return res;
}
| static char* redirectingreason2str | ( | int | redirectingreason | ) | [static] |
Definition at line 1306 of file sig_pri.c.
Referenced by pri_dchannel().
{
switch (redirectingreason) {
case 0:
return "UNKNOWN";
case 1:
return "BUSY";
case 2:
return "NO_REPLY";
case 0xF:
return "UNCONDITIONAL";
default:
return "NOREDIRECT";
}
}
| int sig_pri_answer | ( | struct sig_pri_chan * | p, |
| struct ast_channel * | ast | ||
| ) |
Definition at line 6677 of file sig_pri.c.
References sig_pri_chan::aoc_s_request_invoke_id, sig_pri_chan::aoc_s_request_invoke_id_valid, ast_setstate(), AST_STATE_UP, sig_pri_chan::call, sig_pri_chan::digital, sig_pri_span::pri, sig_pri_chan::pri, pri_grab(), pri_rel(), sig_pri_chan::proceeding, sig_pri_open_media(), and sig_pri_set_dialing().
Referenced by dahdi_answer().
{
int res = 0;
/* Send a pri acknowledge */
if (!pri_grab(p, p->pri)) {
#if defined(HAVE_PRI_AOC_EVENTS)
if (p->aoc_s_request_invoke_id_valid) {
/* if AOC-S was requested and the invoke id is still present on answer. That means
* no AOC-S rate list was provided, so send a NULL response which will indicate that
* AOC-S is not available */
pri_aoc_s_request_response_send(p->pri->pri, p->call,
p->aoc_s_request_invoke_id, NULL);
p->aoc_s_request_invoke_id_valid = 0;
}
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
p->proceeding = 1;
sig_pri_set_dialing(p, 0);
sig_pri_open_media(p);
res = pri_answer(p->pri->pri, p->call, 0, !p->digital);
pri_rel(p->pri);
} else {
res = -1;
}
ast_setstate(ast, AST_STATE_UP);
return res;
}
| static enum ast_aoc_s_charged_item sig_pri_aoc_charged_item_to_ast | ( | enum PRI_AOC_CHARGED_ITEM | value | ) | [static] |
Definition at line 2573 of file sig_pri.c.
References AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION, AST_AOC_CHARGED_ITEM_CALL_ATTEMPT, AST_AOC_CHARGED_ITEM_CALL_SETUP, AST_AOC_CHARGED_ITEM_NA, AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT, AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE, and AST_AOC_CHARGED_ITEM_USER_USER_INFO.
Referenced by sig_pri_aoc_s_from_pri().
{
switch (value) {
case PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE:
return AST_AOC_CHARGED_ITEM_NA;
case PRI_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT:
return AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
case PRI_AOC_CHARGED_ITEM_BASIC_COMMUNICATION:
return AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION;
case PRI_AOC_CHARGED_ITEM_CALL_ATTEMPT:
return AST_AOC_CHARGED_ITEM_CALL_ATTEMPT;
case PRI_AOC_CHARGED_ITEM_CALL_SETUP:
return AST_AOC_CHARGED_ITEM_CALL_SETUP;
case PRI_AOC_CHARGED_ITEM_USER_USER_INFO:
return AST_AOC_CHARGED_ITEM_USER_USER_INFO;
case PRI_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE:
return AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE;
}
return AST_AOC_CHARGED_ITEM_NA;
}
| static enum PRI_AOC_CHARGED_ITEM sig_pri_aoc_charged_item_to_pri | ( | enum PRI_AOC_CHARGED_ITEM | value | ) | [static] |
Definition at line 2541 of file sig_pri.c.
References AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION, AST_AOC_CHARGED_ITEM_CALL_ATTEMPT, AST_AOC_CHARGED_ITEM_CALL_SETUP, AST_AOC_CHARGED_ITEM_NA, AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT, AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE, and AST_AOC_CHARGED_ITEM_USER_USER_INFO.
Referenced by sig_pri_aoc_s_from_ast().
{
switch (value) {
case AST_AOC_CHARGED_ITEM_NA:
return PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE;
case AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT:
return PRI_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
case AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION:
return PRI_AOC_CHARGED_ITEM_BASIC_COMMUNICATION;
case AST_AOC_CHARGED_ITEM_CALL_ATTEMPT:
return PRI_AOC_CHARGED_ITEM_CALL_ATTEMPT;
case AST_AOC_CHARGED_ITEM_CALL_SETUP:
return PRI_AOC_CHARGED_ITEM_CALL_SETUP;
case AST_AOC_CHARGED_ITEM_USER_USER_INFO:
return PRI_AOC_CHARGED_ITEM_USER_USER_INFO;
case AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE:
return PRI_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE;
}
return PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE;
}
| static void sig_pri_aoc_d_from_ast | ( | struct sig_pri_chan * | pvt, |
| struct ast_aoc_decoded * | decoded | ||
| ) | [static] |
Definition at line 3229 of file sig_pri.c.
References ast_aoc_unit_entry::amount, ARRAY_LEN, AST_AOC_BILLING_CREDIT_CARD, AST_AOC_BILLING_NA, AST_AOC_BILLING_NORMAL, AST_AOC_BILLING_REVERSE_CHARGE, AST_AOC_CHARGE_CURRENCY, AST_AOC_CHARGE_FREE, AST_AOC_CHARGE_NA, AST_AOC_CHARGE_UNIT, ast_aoc_get_billing_id(), ast_aoc_get_charge_type(), ast_aoc_get_currency_amount(), ast_aoc_get_currency_multiplier(), ast_aoc_get_currency_name(), ast_aoc_get_total_type(), ast_aoc_get_unit_count(), ast_aoc_get_unit_info(), AST_AOC_TOTAL, ast_copy_string(), ast_strlen_zero(), sig_pri_chan::call, sig_pri_span::pri, sig_pri_chan::pri, sig_pri_aoc_multiplier_from_ast(), ast_aoc_unit_entry::type, ast_aoc_unit_entry::valid_amount, and ast_aoc_unit_entry::valid_type.
Referenced by sig_pri_indicate().
{
struct pri_subcmd_aoc_d aoc_d = { 0, };
aoc_d.billing_accumulation = (ast_aoc_get_total_type(decoded) == AST_AOC_TOTAL) ? 1 : 0;
switch (ast_aoc_get_billing_id(decoded)) {
case AST_AOC_BILLING_NORMAL:
aoc_d.billing_id = PRI_AOC_D_BILLING_ID_NORMAL;
break;
case AST_AOC_BILLING_REVERSE_CHARGE:
aoc_d.billing_id = PRI_AOC_D_BILLING_ID_REVERSE;
break;
case AST_AOC_BILLING_CREDIT_CARD:
aoc_d.billing_id = PRI_AOC_D_BILLING_ID_CREDIT_CARD;
break;
case AST_AOC_BILLING_NA:
default:
aoc_d.billing_id = PRI_AOC_D_BILLING_ID_NOT_AVAILABLE;
break;
}
switch (ast_aoc_get_charge_type(decoded)) {
case AST_AOC_CHARGE_FREE:
aoc_d.charge = PRI_AOC_DE_CHARGE_FREE;
break;
case AST_AOC_CHARGE_CURRENCY:
{
const char *currency_name = ast_aoc_get_currency_name(decoded);
aoc_d.charge = PRI_AOC_DE_CHARGE_CURRENCY;
aoc_d.recorded.money.amount.cost = ast_aoc_get_currency_amount(decoded);
aoc_d.recorded.money.amount.multiplier = sig_pri_aoc_multiplier_from_ast(ast_aoc_get_currency_multiplier(decoded));
if (!ast_strlen_zero(currency_name)) {
ast_copy_string(aoc_d.recorded.money.currency, currency_name, sizeof(aoc_d.recorded.money.currency));
}
}
break;
case AST_AOC_CHARGE_UNIT:
{
const struct ast_aoc_unit_entry *entry;
int i;
aoc_d.charge = PRI_AOC_DE_CHARGE_UNITS;
for (i = 0; i < ast_aoc_get_unit_count(decoded); i++) {
if ((entry = ast_aoc_get_unit_info(decoded, i)) && i < ARRAY_LEN(aoc_d.recorded.unit.item)) {
if (entry->valid_amount) {
aoc_d.recorded.unit.item[i].number = entry->amount;
} else {
aoc_d.recorded.unit.item[i].number = -1;
}
if (entry->valid_type) {
aoc_d.recorded.unit.item[i].type = entry->type;
} else {
aoc_d.recorded.unit.item[i].type = -1;
}
aoc_d.recorded.unit.num_items++;
} else {
break;
}
}
}
break;
case AST_AOC_CHARGE_NA:
default:
aoc_d.charge = PRI_AOC_DE_CHARGE_NOT_AVAILABLE;
break;
}
pri_aoc_d_send(pvt->pri->pri, pvt->call, &aoc_d);
}
| static void sig_pri_aoc_d_from_pri | ( | const struct pri_subcmd_aoc_d * | aoc_d, |
| struct ast_channel * | owner, | ||
| int | passthrough | ||
| ) | [static] |
Definition at line 2902 of file sig_pri.c.
References ast_aoc_add_unit_entry(), AST_AOC_BILLING_CREDIT_CARD, AST_AOC_BILLING_NA, AST_AOC_BILLING_NORMAL, AST_AOC_BILLING_REVERSE_CHARGE, AST_AOC_CHARGE_CURRENCY, AST_AOC_CHARGE_FREE, AST_AOC_CHARGE_NA, AST_AOC_CHARGE_UNIT, ast_aoc_create(), AST_AOC_D, ast_aoc_destroy_decoded(), ast_aoc_destroy_encoded(), ast_aoc_encode(), ast_aoc_manager_event(), ast_aoc_set_billing_id(), ast_aoc_set_currency_info(), ast_aoc_set_total_type(), AST_AOC_SUBTOTAL, AST_AOC_TOTAL, AST_CONTROL_AOC, ast_debug, ast_queue_control_data(), sig_pri_aoc_multiplier_from_pri(), and type.
Referenced by sig_pri_handle_subcmds().
{
struct ast_aoc_decoded *decoded = NULL;
struct ast_aoc_encoded *encoded = NULL;
size_t encoded_size = 0;
enum ast_aoc_charge_type type;
if (!owner || !aoc_d) {
return;
}
switch (aoc_d->charge) {
case PRI_AOC_DE_CHARGE_CURRENCY:
type = AST_AOC_CHARGE_CURRENCY;
break;
case PRI_AOC_DE_CHARGE_UNITS:
type = AST_AOC_CHARGE_UNIT;
break;
case PRI_AOC_DE_CHARGE_FREE:
type = AST_AOC_CHARGE_FREE;
break;
default:
type = AST_AOC_CHARGE_NA;
break;
}
if (!(decoded = ast_aoc_create(AST_AOC_D, type, 0))) {
return;
}
switch (aoc_d->billing_accumulation) {
default:
ast_debug(1, "AOC-D billing accumulation has unknown value: %d\n",
aoc_d->billing_accumulation);
/* Fall through */
case 0:/* subTotal */
ast_aoc_set_total_type(decoded, AST_AOC_SUBTOTAL);
break;
case 1:/* total */
ast_aoc_set_total_type(decoded, AST_AOC_TOTAL);
break;
}
switch (aoc_d->billing_id) {
case PRI_AOC_D_BILLING_ID_NORMAL:
ast_aoc_set_billing_id(decoded, AST_AOC_BILLING_NORMAL);
break;
case PRI_AOC_D_BILLING_ID_REVERSE:
ast_aoc_set_billing_id(decoded, AST_AOC_BILLING_REVERSE_CHARGE);
break;
case PRI_AOC_D_BILLING_ID_CREDIT_CARD:
ast_aoc_set_billing_id(decoded, AST_AOC_BILLING_CREDIT_CARD);
break;
case PRI_AOC_D_BILLING_ID_NOT_AVAILABLE:
default:
ast_aoc_set_billing_id(decoded, AST_AOC_BILLING_NA);
break;
}
switch (aoc_d->charge) {
case PRI_AOC_DE_CHARGE_CURRENCY:
ast_aoc_set_currency_info(decoded,
aoc_d->recorded.money.amount.cost,
sig_pri_aoc_multiplier_from_pri(aoc_d->recorded.money.amount.multiplier),
aoc_d->recorded.money.currency);
break;
case PRI_AOC_DE_CHARGE_UNITS:
{
int i;
for (i = 0; i < aoc_d->recorded.unit.num_items; ++i) {
/* if type or number are negative, then they are not present */
ast_aoc_add_unit_entry(decoded,
(aoc_d->recorded.unit.item[i].number >= 0 ? 1 : 0),
aoc_d->recorded.unit.item[i].number,
(aoc_d->recorded.unit.item[i].type >= 0 ? 1 : 0),
aoc_d->recorded.unit.item[i].type);
}
}
break;
}
if (passthrough && (encoded = ast_aoc_encode(decoded, &encoded_size, owner))) {
ast_queue_control_data(owner, AST_CONTROL_AOC, encoded, encoded_size);
}
ast_aoc_manager_event(decoded, owner);
ast_aoc_destroy_decoded(decoded);
ast_aoc_destroy_encoded(encoded);
}
| static void sig_pri_aoc_e_from_ast | ( | struct sig_pri_chan * | pvt, |
| struct ast_aoc_decoded * | decoded | ||
| ) | [static] |
Definition at line 3312 of file sig_pri.c.
References ast_aoc_unit_entry::amount, sig_pri_chan::aoc_e, ARRAY_LEN, AST_AOC_BILLING_CALL_DEFLECTION, AST_AOC_BILLING_CALL_FWD_BUSY, AST_AOC_BILLING_CALL_FWD_NO_REPLY, AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL, AST_AOC_BILLING_CALL_TRANSFER, AST_AOC_BILLING_CREDIT_CARD, AST_AOC_BILLING_NA, AST_AOC_BILLING_NORMAL, AST_AOC_BILLING_REVERSE_CHARGE, AST_AOC_CHARGE_CURRENCY, AST_AOC_CHARGE_FREE, AST_AOC_CHARGE_NA, AST_AOC_CHARGE_UNIT, AST_AOC_CHARGING_ASSOCIATION_ID, AST_AOC_CHARGING_ASSOCIATION_NA, AST_AOC_CHARGING_ASSOCIATION_NUMBER, ast_aoc_get_association_info(), ast_aoc_get_billing_id(), ast_aoc_get_charge_type(), ast_aoc_get_currency_amount(), ast_aoc_get_currency_multiplier(), ast_aoc_get_currency_name(), ast_aoc_get_unit_count(), ast_aoc_get_unit_info(), ast_copy_string(), ast_strlen_zero(), ast_aoc_charging_association::charge, ast_aoc_charging_association::charging_type, sig_pri_chan::holding_aoce, ast_aoc_charging_association::id, ast_aoc_charging_association_number::number, ast_aoc_charging_association::number, ast_aoc_charging_association_number::plan, sig_pri_aoc_multiplier_from_ast(), ast_aoc_unit_entry::type, ast_aoc_unit_entry::valid_amount, and ast_aoc_unit_entry::valid_type.
Referenced by sig_pri_indicate().
{
struct pri_subcmd_aoc_e *aoc_e = &pvt->aoc_e;
const struct ast_aoc_charging_association *ca = ast_aoc_get_association_info(decoded);
memset(aoc_e, 0, sizeof(*aoc_e));
pvt->holding_aoce = 1;
switch (ca->charging_type) {
case AST_AOC_CHARGING_ASSOCIATION_NUMBER:
aoc_e->associated.charge.number.valid = 1;
ast_copy_string(aoc_e->associated.charge.number.str,
ca->charge.number.number,
sizeof(aoc_e->associated.charge.number.str));
aoc_e->associated.charge.number.plan = ca->charge.number.plan;
aoc_e->associated.charging_type = PRI_AOC_E_CHARGING_ASSOCIATION_NUMBER;
break;
case AST_AOC_CHARGING_ASSOCIATION_ID:
aoc_e->associated.charge.id = ca->charge.id;
aoc_e->associated.charging_type = PRI_AOC_E_CHARGING_ASSOCIATION_ID;
break;
case AST_AOC_CHARGING_ASSOCIATION_NA:
default:
break;
}
switch (ast_aoc_get_billing_id(decoded)) {
case AST_AOC_BILLING_NORMAL:
aoc_e->billing_id = PRI_AOC_E_BILLING_ID_NORMAL;
break;
case AST_AOC_BILLING_REVERSE_CHARGE:
aoc_e->billing_id = PRI_AOC_E_BILLING_ID_REVERSE;
break;
case AST_AOC_BILLING_CREDIT_CARD:
aoc_e->billing_id = PRI_AOC_E_BILLING_ID_CREDIT_CARD;
break;
case AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL:
aoc_e->billing_id = PRI_AOC_E_BILLING_ID_CALL_FORWARDING_UNCONDITIONAL;
break;
case AST_AOC_BILLING_CALL_FWD_BUSY:
aoc_e->billing_id = PRI_AOC_E_BILLING_ID_CALL_FORWARDING_BUSY;
break;
case AST_AOC_BILLING_CALL_FWD_NO_REPLY:
aoc_e->billing_id = PRI_AOC_E_BILLING_ID_CALL_FORWARDING_NO_REPLY;
break;
case AST_AOC_BILLING_CALL_DEFLECTION:
aoc_e->billing_id = PRI_AOC_E_BILLING_ID_CALL_DEFLECTION;
break;
case AST_AOC_BILLING_CALL_TRANSFER:
aoc_e->billing_id = PRI_AOC_E_BILLING_ID_CALL_TRANSFER;
break;
case AST_AOC_BILLING_NA:
default:
aoc_e->billing_id = PRI_AOC_E_BILLING_ID_NOT_AVAILABLE;
break;
}
switch (ast_aoc_get_charge_type(decoded)) {
case AST_AOC_CHARGE_FREE:
aoc_e->charge = PRI_AOC_DE_CHARGE_FREE;
break;
case AST_AOC_CHARGE_CURRENCY:
{
const char *currency_name = ast_aoc_get_currency_name(decoded);
aoc_e->charge = PRI_AOC_DE_CHARGE_CURRENCY;
aoc_e->recorded.money.amount.cost = ast_aoc_get_currency_amount(decoded);
aoc_e->recorded.money.amount.multiplier = sig_pri_aoc_multiplier_from_ast(ast_aoc_get_currency_multiplier(decoded));
if (!ast_strlen_zero(currency_name)) {
ast_copy_string(aoc_e->recorded.money.currency, currency_name, sizeof(aoc_e->recorded.money.currency));
}
}
break;
case AST_AOC_CHARGE_UNIT:
{
const struct ast_aoc_unit_entry *entry;
int i;
aoc_e->charge = PRI_AOC_DE_CHARGE_UNITS;
for (i = 0; i < ast_aoc_get_unit_count(decoded); i++) {
if ((entry = ast_aoc_get_unit_info(decoded, i)) && i < ARRAY_LEN(aoc_e->recorded.unit.item)) {
if (entry->valid_amount) {
aoc_e->recorded.unit.item[i].number = entry->amount;
} else {
aoc_e->recorded.unit.item[i].number = -1;
}
if (entry->valid_type) {
aoc_e->recorded.unit.item[i].type = entry->type;
} else {
aoc_e->recorded.unit.item[i].type = -1;
}
aoc_e->recorded.unit.num_items++;
}
}
}
break;
case AST_AOC_CHARGE_NA:
default:
aoc_e->charge = PRI_AOC_DE_CHARGE_NOT_AVAILABLE;
break;
}
}
| static void sig_pri_aoc_e_from_pri | ( | const struct pri_subcmd_aoc_e * | aoc_e, |
| struct ast_channel * | owner, | ||
| int | passthrough | ||
| ) | [static] |
Definition at line 3011 of file sig_pri.c.
References ast_aoc_add_unit_entry(), AST_AOC_BILLING_CALL_DEFLECTION, AST_AOC_BILLING_CALL_FWD_BUSY, AST_AOC_BILLING_CALL_FWD_NO_REPLY, AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL, AST_AOC_BILLING_CALL_TRANSFER, AST_AOC_BILLING_CREDIT_CARD, AST_AOC_BILLING_NA, AST_AOC_BILLING_NORMAL, AST_AOC_BILLING_REVERSE_CHARGE, AST_AOC_CHARGE_CURRENCY, AST_AOC_CHARGE_FREE, AST_AOC_CHARGE_NA, AST_AOC_CHARGE_UNIT, ast_aoc_create(), ast_aoc_destroy_decoded(), ast_aoc_destroy_encoded(), AST_AOC_E, ast_aoc_encode(), ast_aoc_manager_event(), ast_aoc_set_association_id(), ast_aoc_set_association_number(), ast_aoc_set_billing_id(), ast_aoc_set_currency_info(), AST_CONTROL_AOC, ast_queue_control_data(), sig_pri_aoc_multiplier_from_pri(), and type.
Referenced by sig_pri_handle_cis_subcmds(), and sig_pri_handle_subcmds().
{
struct ast_aoc_decoded *decoded = NULL;
struct ast_aoc_encoded *encoded = NULL;
size_t encoded_size = 0;
enum ast_aoc_charge_type type;
if (!aoc_e) {
return;
}
switch (aoc_e->charge) {
case PRI_AOC_DE_CHARGE_CURRENCY:
type = AST_AOC_CHARGE_CURRENCY;
break;
case PRI_AOC_DE_CHARGE_UNITS:
type = AST_AOC_CHARGE_UNIT;
break;
case PRI_AOC_DE_CHARGE_FREE:
type = AST_AOC_CHARGE_FREE;
break;
default:
type = AST_AOC_CHARGE_NA;
break;
}
if (!(decoded = ast_aoc_create(AST_AOC_E, type, 0))) {
return;
}
switch (aoc_e->associated.charging_type) {
case PRI_AOC_E_CHARGING_ASSOCIATION_NUMBER:
if (!aoc_e->associated.charge.number.valid) {
break;
}
ast_aoc_set_association_number(decoded, aoc_e->associated.charge.number.str, aoc_e->associated.charge.number.plan);
break;
case PRI_AOC_E_CHARGING_ASSOCIATION_ID:
ast_aoc_set_association_id(decoded, aoc_e->associated.charge.id);
break;
default:
break;
}
switch (aoc_e->billing_id) {
case PRI_AOC_E_BILLING_ID_NORMAL:
ast_aoc_set_billing_id(decoded, AST_AOC_BILLING_NORMAL);
break;
case PRI_AOC_E_BILLING_ID_REVERSE:
ast_aoc_set_billing_id(decoded, AST_AOC_BILLING_REVERSE_CHARGE);
break;
case PRI_AOC_E_BILLING_ID_CREDIT_CARD:
ast_aoc_set_billing_id(decoded, AST_AOC_BILLING_CREDIT_CARD);
break;
case PRI_AOC_E_BILLING_ID_CALL_FORWARDING_UNCONDITIONAL:
ast_aoc_set_billing_id(decoded, AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL);
break;
case PRI_AOC_E_BILLING_ID_CALL_FORWARDING_BUSY:
ast_aoc_set_billing_id(decoded, AST_AOC_BILLING_CALL_FWD_BUSY);
break;
case PRI_AOC_E_BILLING_ID_CALL_FORWARDING_NO_REPLY:
ast_aoc_set_billing_id(decoded, AST_AOC_BILLING_CALL_FWD_NO_REPLY);
break;
case PRI_AOC_E_BILLING_ID_CALL_DEFLECTION:
ast_aoc_set_billing_id(decoded, AST_AOC_BILLING_CALL_DEFLECTION);
break;
case PRI_AOC_E_BILLING_ID_CALL_TRANSFER:
ast_aoc_set_billing_id(decoded, AST_AOC_BILLING_CALL_TRANSFER);
break;
case PRI_AOC_E_BILLING_ID_NOT_AVAILABLE:
default:
ast_aoc_set_billing_id(decoded, AST_AOC_BILLING_NA);
break;
}
switch (aoc_e->charge) {
case PRI_AOC_DE_CHARGE_CURRENCY:
ast_aoc_set_currency_info(decoded,
aoc_e->recorded.money.amount.cost,
sig_pri_aoc_multiplier_from_pri(aoc_e->recorded.money.amount.multiplier),
aoc_e->recorded.money.currency);
break;
case PRI_AOC_DE_CHARGE_UNITS:
{
int i;
for (i = 0; i < aoc_e->recorded.unit.num_items; ++i) {
/* if type or number are negative, then they are not present */
ast_aoc_add_unit_entry(decoded,
(aoc_e->recorded.unit.item[i].number >= 0 ? 1 : 0),
aoc_e->recorded.unit.item[i].number,
(aoc_e->recorded.unit.item[i].type >= 0 ? 1 : 0),
aoc_e->recorded.unit.item[i].type);
}
}
}
if (passthrough && owner && (encoded = ast_aoc_encode(decoded, &encoded_size, owner))) {
ast_queue_control_data(owner, AST_CONTROL_AOC, encoded, encoded_size);
}
ast_aoc_manager_event(decoded, owner);
ast_aoc_destroy_decoded(decoded);
ast_aoc_destroy_encoded(encoded);
}
| static int sig_pri_aoc_multiplier_from_ast | ( | enum ast_aoc_currency_multiplier | mult | ) | [static] |
Definition at line 2603 of file sig_pri.c.
References AST_AOC_MULT_HUNDRED, AST_AOC_MULT_ONE, AST_AOC_MULT_ONEHUNDREDTH, AST_AOC_MULT_ONETENTH, AST_AOC_MULT_ONETHOUSANDTH, AST_AOC_MULT_TEN, and AST_AOC_MULT_THOUSAND.
Referenced by sig_pri_aoc_d_from_ast(), sig_pri_aoc_e_from_ast(), and sig_pri_aoc_s_from_ast().
{
switch (mult) {
case AST_AOC_MULT_ONETHOUSANDTH:
return PRI_AOC_MULTIPLIER_THOUSANDTH;
case AST_AOC_MULT_ONEHUNDREDTH:
return PRI_AOC_MULTIPLIER_HUNDREDTH;
case AST_AOC_MULT_ONETENTH:
return PRI_AOC_MULTIPLIER_TENTH;
case AST_AOC_MULT_ONE:
return PRI_AOC_MULTIPLIER_ONE;
case AST_AOC_MULT_TEN:
return PRI_AOC_MULTIPLIER_TEN;
case AST_AOC_MULT_HUNDRED:
return PRI_AOC_MULTIPLIER_HUNDRED;
case AST_AOC_MULT_THOUSAND:
return PRI_AOC_MULTIPLIER_THOUSAND;
default:
return PRI_AOC_MULTIPLIER_ONE;
}
}
| static int sig_pri_aoc_multiplier_from_pri | ( | const int | mult | ) | [static] |
Definition at line 2634 of file sig_pri.c.
References AST_AOC_MULT_HUNDRED, AST_AOC_MULT_ONE, AST_AOC_MULT_ONEHUNDREDTH, AST_AOC_MULT_ONETENTH, AST_AOC_MULT_ONETHOUSANDTH, AST_AOC_MULT_TEN, and AST_AOC_MULT_THOUSAND.
Referenced by sig_pri_aoc_d_from_pri(), sig_pri_aoc_e_from_pri(), and sig_pri_aoc_s_from_pri().
{
switch (mult) {
case PRI_AOC_MULTIPLIER_THOUSANDTH:
return AST_AOC_MULT_ONETHOUSANDTH;
case PRI_AOC_MULTIPLIER_HUNDREDTH:
return AST_AOC_MULT_ONEHUNDREDTH;
case PRI_AOC_MULTIPLIER_TENTH:
return AST_AOC_MULT_ONETENTH;
case PRI_AOC_MULTIPLIER_ONE:
return AST_AOC_MULT_ONE;
case PRI_AOC_MULTIPLIER_TEN:
return AST_AOC_MULT_TEN;
case PRI_AOC_MULTIPLIER_HUNDRED:
return AST_AOC_MULT_HUNDRED;
case PRI_AOC_MULTIPLIER_THOUSAND:
return AST_AOC_MULT_THOUSAND;
default:
return AST_AOC_MULT_ONE;
}
}
| static void sig_pri_aoc_request_from_pri | ( | const struct pri_subcmd_aoc_request * | aoc_request, |
| struct sig_pri_chan * | pvt, | ||
| q931_call * | call | ||
| ) | [static] |
Definition at line 2831 of file sig_pri.c.
References sig_pri_span::aoc_passthrough_flag, sig_pri_chan::aoc_s_request_invoke_id, sig_pri_chan::aoc_s_request_invoke_id_valid, sig_pri_span::pri, sig_pri_chan::pri, SIG_PRI_AOC_GRANT_D, SIG_PRI_AOC_GRANT_E, and SIG_PRI_AOC_GRANT_S.
Referenced by sig_pri_handle_subcmds().
{
int request;
if (!aoc_request) {
return;
}
request = aoc_request->charging_request;
if (request & PRI_AOC_REQUEST_S) {
if (pvt->pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_S) {
/* An AOC-S response must come from the other side, so save off this invoke_id
* and see if an AOC-S message comes in before the call is answered. */
pvt->aoc_s_request_invoke_id = aoc_request->invoke_id;
pvt->aoc_s_request_invoke_id_valid = 1;
} else {
pri_aoc_s_request_response_send(pvt->pri->pri,
call,
aoc_request->invoke_id,
NULL);
}
}
if (request & PRI_AOC_REQUEST_D) {
if (pvt->pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_D) {
pri_aoc_de_request_response_send(pvt->pri->pri,
call,
PRI_AOC_REQ_RSP_CHARGING_INFO_FOLLOWS,
aoc_request->invoke_id);
} else {
pri_aoc_de_request_response_send(pvt->pri->pri,
call,
PRI_AOC_REQ_RSP_ERROR_NOT_AVAILABLE,
aoc_request->invoke_id);
}
}
if (request & PRI_AOC_REQUEST_E) {
if (pvt->pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_E) {
pri_aoc_de_request_response_send(pvt->pri->pri,
call,
PRI_AOC_REQ_RSP_CHARGING_INFO_FOLLOWS,
aoc_request->invoke_id);
} else {
pri_aoc_de_request_response_send(pvt->pri->pri,
call,
PRI_AOC_REQ_RSP_ERROR_NOT_AVAILABLE,
aoc_request->invoke_id);
}
}
}
| static void sig_pri_aoc_s_from_ast | ( | struct sig_pri_chan * | pvt, |
| struct ast_aoc_decoded * | decoded | ||
| ) | [static] |
Definition at line 3130 of file sig_pri.c.
References ast_aoc_volume_rate::amount, ast_aoc_flat_rate::amount, ast_aoc_duration_rate::amount, sig_pri_chan::aoc_s_request_invoke_id, sig_pri_chan::aoc_s_request_invoke_id_valid, AST_AOC_RATE_TYPE_DURATION, AST_AOC_RATE_TYPE_FLAT, AST_AOC_RATE_TYPE_FREE, AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING, AST_AOC_RATE_TYPE_NA, AST_AOC_RATE_TYPE_SPECIAL_CODE, AST_AOC_RATE_TYPE_VOLUME, ast_aoc_s_get_count(), ast_aoc_s_get_rate_info(), ast_copy_string(), ast_strlen_zero(), sig_pri_chan::call, ast_aoc_s_entry::charged_item, ast_aoc_duration_rate::charging_type, ast_aoc_volume_rate::currency_name, ast_aoc_flat_rate::currency_name, ast_aoc_duration_rate::currency_name, ast_aoc_s_entry::duration, ast_aoc_s_entry::flat, ast_aoc_duration_rate::granularity_time, ast_aoc_duration_rate::granularity_time_scale, ast_aoc_volume_rate::multiplier, ast_aoc_flat_rate::multiplier, ast_aoc_duration_rate::multiplier, sig_pri_span::pri, sig_pri_chan::pri, ast_aoc_s_entry::rate, ast_aoc_s_entry::rate_type, sig_pri_aoc_charged_item_to_pri(), sig_pri_aoc_multiplier_from_ast(), sig_pri_aoc_scale_to_pri(), ast_aoc_s_entry::special_code, ast_aoc_duration_rate::time, ast_aoc_duration_rate::time_scale, ast_aoc_s_entry::volume, and ast_aoc_volume_rate::volume_unit.
Referenced by sig_pri_indicate().
{
struct pri_subcmd_aoc_s aoc_s = { 0, };
const struct ast_aoc_s_entry *entry;
int idx;
for (idx = 0; idx < ast_aoc_s_get_count(decoded); idx++) {
if (!(entry = ast_aoc_s_get_rate_info(decoded, idx))) {
break;
}
aoc_s.item[idx].chargeable = sig_pri_aoc_charged_item_to_pri(entry->charged_item);
switch (entry->rate_type) {
case AST_AOC_RATE_TYPE_DURATION:
aoc_s.item[idx].rate_type = PRI_AOC_RATE_TYPE_DURATION;
aoc_s.item[idx].rate.duration.amount.cost = entry->rate.duration.amount;
aoc_s.item[idx].rate.duration.amount.multiplier =
sig_pri_aoc_multiplier_from_ast(entry->rate.duration.multiplier);
aoc_s.item[idx].rate.duration.time.length = entry->rate.duration.time;
aoc_s.item[idx].rate.duration.time.scale =
sig_pri_aoc_scale_to_pri(entry->rate.duration.time_scale);
aoc_s.item[idx].rate.duration.granularity.length = entry->rate.duration.granularity_time;
aoc_s.item[idx].rate.duration.granularity.scale =
sig_pri_aoc_scale_to_pri(entry->rate.duration.granularity_time_scale);
aoc_s.item[idx].rate.duration.charging_type = entry->rate.duration.charging_type;
if (!ast_strlen_zero(entry->rate.duration.currency_name)) {
ast_copy_string(aoc_s.item[idx].rate.duration.currency,
entry->rate.duration.currency_name,
sizeof(aoc_s.item[idx].rate.duration.currency));
}
break;
case AST_AOC_RATE_TYPE_FLAT:
aoc_s.item[idx].rate_type = PRI_AOC_RATE_TYPE_FLAT;
aoc_s.item[idx].rate.flat.amount.cost = entry->rate.flat.amount;
aoc_s.item[idx].rate.flat.amount.multiplier =
sig_pri_aoc_multiplier_from_ast(entry->rate.flat.multiplier);
if (!ast_strlen_zero(entry->rate.flat.currency_name)) {
ast_copy_string(aoc_s.item[idx].rate.flat.currency,
entry->rate.flat.currency_name,
sizeof(aoc_s.item[idx].rate.flat.currency));
}
break;
case AST_AOC_RATE_TYPE_VOLUME:
aoc_s.item[idx].rate_type = PRI_AOC_RATE_TYPE_VOLUME;
aoc_s.item[idx].rate.volume.unit = entry->rate.volume.volume_unit;
aoc_s.item[idx].rate.volume.amount.cost = entry->rate.volume.amount;
aoc_s.item[idx].rate.volume.amount.multiplier =
sig_pri_aoc_multiplier_from_ast(entry->rate.volume.multiplier);
if (!ast_strlen_zero(entry->rate.volume.currency_name)) {
ast_copy_string(aoc_s.item[idx].rate.volume.currency,
entry->rate.volume.currency_name,
sizeof(aoc_s.item[idx].rate.volume.currency));
}
break;
case AST_AOC_RATE_TYPE_SPECIAL_CODE:
aoc_s.item[idx].rate_type = PRI_AOC_RATE_TYPE_SPECIAL_CODE;
aoc_s.item[idx].rate.special = entry->rate.special_code;
break;
case AST_AOC_RATE_TYPE_FREE:
aoc_s.item[idx].rate_type = PRI_AOC_RATE_TYPE_FREE;
break;
case AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING:
aoc_s.item[idx].rate_type = PRI_AOC_RATE_TYPE_FREE_FROM_BEGINNING;
break;
default:
case AST_AOC_RATE_TYPE_NA:
aoc_s.item[idx].rate_type = PRI_AOC_RATE_TYPE_NOT_AVAILABLE;
break;
}
}
aoc_s.num_items = idx;
/* if this rate should be sent as a response to an AOC-S request we will
* have an aoc_s_request_invoke_id associated with this pvt */
if (pvt->aoc_s_request_invoke_id_valid) {
pri_aoc_s_request_response_send(pvt->pri->pri, pvt->call, pvt->aoc_s_request_invoke_id, &aoc_s);
pvt->aoc_s_request_invoke_id_valid = 0;
} else {
pri_aoc_s_send(pvt->pri->pri, pvt->call, &aoc_s);
}
}
| static void sig_pri_aoc_s_from_pri | ( | const struct pri_subcmd_aoc_s * | aoc_s, |
| struct ast_channel * | owner, | ||
| int | passthrough | ||
| ) | [static] |
Definition at line 2738 of file sig_pri.c.
References AST_AOC_CHARGED_ITEM_NA, ast_aoc_create(), ast_aoc_destroy_decoded(), ast_aoc_destroy_encoded(), ast_aoc_encode(), ast_aoc_manager_event(), AST_AOC_S, ast_aoc_s_add_rate_duration(), ast_aoc_s_add_rate_flat(), ast_aoc_s_add_rate_free(), ast_aoc_s_add_rate_na(), ast_aoc_s_add_rate_special_charge_code(), ast_aoc_s_add_rate_volume(), AST_CONTROL_AOC, ast_queue_control_data(), sig_pri_aoc_charged_item_to_ast(), sig_pri_aoc_multiplier_from_pri(), and sig_pri_aoc_scale_to_ast().
Referenced by sig_pri_handle_subcmds().
{
struct ast_aoc_decoded *decoded = NULL;
struct ast_aoc_encoded *encoded = NULL;
size_t encoded_size = 0;
int idx;
if (!owner || !aoc_s) {
return;
}
if (!(decoded = ast_aoc_create(AST_AOC_S, 0, 0))) {
return;
}
for (idx = 0; idx < aoc_s->num_items; ++idx) {
enum ast_aoc_s_charged_item charged_item;
charged_item = sig_pri_aoc_charged_item_to_ast(aoc_s->item[idx].chargeable);
if (charged_item == AST_AOC_CHARGED_ITEM_NA) {
/* Delete the unknown charged item from the list. */
continue;
}
switch (aoc_s->item[idx].rate_type) {
case PRI_AOC_RATE_TYPE_DURATION:
ast_aoc_s_add_rate_duration(decoded,
charged_item,
aoc_s->item[idx].rate.duration.amount.cost,
sig_pri_aoc_multiplier_from_pri(aoc_s->item[idx].rate.duration.amount.multiplier),
aoc_s->item[idx].rate.duration.currency,
aoc_s->item[idx].rate.duration.time.length,
sig_pri_aoc_scale_to_ast(aoc_s->item[idx].rate.duration.time.scale),
aoc_s->item[idx].rate.duration.granularity.length,
sig_pri_aoc_scale_to_ast(aoc_s->item[idx].rate.duration.granularity.scale),
aoc_s->item[idx].rate.duration.charging_type);
break;
case PRI_AOC_RATE_TYPE_FLAT:
ast_aoc_s_add_rate_flat(decoded,
charged_item,
aoc_s->item[idx].rate.flat.amount.cost,
sig_pri_aoc_multiplier_from_pri(aoc_s->item[idx].rate.flat.amount.multiplier),
aoc_s->item[idx].rate.flat.currency);
break;
case PRI_AOC_RATE_TYPE_VOLUME:
ast_aoc_s_add_rate_volume(decoded,
charged_item,
aoc_s->item[idx].rate.volume.unit,
aoc_s->item[idx].rate.volume.amount.cost,
sig_pri_aoc_multiplier_from_pri(aoc_s->item[idx].rate.volume.amount.multiplier),
aoc_s->item[idx].rate.volume.currency);
break;
case PRI_AOC_RATE_TYPE_SPECIAL_CODE:
ast_aoc_s_add_rate_special_charge_code(decoded,
charged_item,
aoc_s->item[idx].rate.special);
break;
case PRI_AOC_RATE_TYPE_FREE:
ast_aoc_s_add_rate_free(decoded, charged_item, 0);
break;
case PRI_AOC_RATE_TYPE_FREE_FROM_BEGINNING:
ast_aoc_s_add_rate_free(decoded, charged_item, 1);
break;
default:
ast_aoc_s_add_rate_na(decoded, charged_item);
break;
}
}
if (passthrough && (encoded = ast_aoc_encode(decoded, &encoded_size, owner))) {
ast_queue_control_data(owner, AST_CONTROL_AOC, encoded, encoded_size);
}
ast_aoc_manager_event(decoded, owner);
ast_aoc_destroy_decoded(decoded);
ast_aoc_destroy_encoded(encoded);
}
| static enum ast_aoc_time_scale sig_pri_aoc_scale_to_ast | ( | enum PRI_AOC_TIME_SCALE | value | ) | [static] |
Definition at line 2699 of file sig_pri.c.
References AST_AOC_TIME_SCALE_DAY, AST_AOC_TIME_SCALE_HOUR, AST_AOC_TIME_SCALE_HUNDREDTH_SECOND, AST_AOC_TIME_SCALE_MINUTE, AST_AOC_TIME_SCALE_SECOND, AST_AOC_TIME_SCALE_TEN_SECOND, and AST_AOC_TIME_SCALE_TENTH_SECOND.
Referenced by sig_pri_aoc_s_from_pri().
{
switch (value) {
default:
case PRI_AOC_TIME_SCALE_HUNDREDTH_SECOND:
return AST_AOC_TIME_SCALE_HUNDREDTH_SECOND;
case PRI_AOC_TIME_SCALE_TENTH_SECOND:
return AST_AOC_TIME_SCALE_TENTH_SECOND;
case PRI_AOC_TIME_SCALE_SECOND:
return AST_AOC_TIME_SCALE_SECOND;
case PRI_AOC_TIME_SCALE_TEN_SECOND:
return AST_AOC_TIME_SCALE_TEN_SECOND;
case PRI_AOC_TIME_SCALE_MINUTE:
return AST_AOC_TIME_SCALE_MINUTE;
case PRI_AOC_TIME_SCALE_HOUR:
return AST_AOC_TIME_SCALE_HOUR;
case PRI_AOC_TIME_SCALE_DAY:
return AST_AOC_TIME_SCALE_DAY;
}
return AST_AOC_TIME_SCALE_HUNDREDTH_SECOND;
}
| static enum PRI_AOC_TIME_SCALE sig_pri_aoc_scale_to_pri | ( | enum ast_aoc_time_scale | value | ) | [static] |
Definition at line 2667 of file sig_pri.c.
References AST_AOC_TIME_SCALE_DAY, AST_AOC_TIME_SCALE_HOUR, AST_AOC_TIME_SCALE_HUNDREDTH_SECOND, AST_AOC_TIME_SCALE_MINUTE, AST_AOC_TIME_SCALE_SECOND, AST_AOC_TIME_SCALE_TEN_SECOND, and AST_AOC_TIME_SCALE_TENTH_SECOND.
Referenced by sig_pri_aoc_s_from_ast().
{
switch (value) {
default:
case AST_AOC_TIME_SCALE_HUNDREDTH_SECOND:
return PRI_AOC_TIME_SCALE_HUNDREDTH_SECOND;
case AST_AOC_TIME_SCALE_TENTH_SECOND:
return PRI_AOC_TIME_SCALE_TENTH_SECOND;
case AST_AOC_TIME_SCALE_SECOND:
return PRI_AOC_TIME_SCALE_SECOND;
case AST_AOC_TIME_SCALE_TEN_SECOND:
return PRI_AOC_TIME_SCALE_TEN_SECOND;
case AST_AOC_TIME_SCALE_MINUTE:
return PRI_AOC_TIME_SCALE_MINUTE;
case AST_AOC_TIME_SCALE_HOUR:
return PRI_AOC_TIME_SCALE_HOUR;
case AST_AOC_TIME_SCALE_DAY:
return PRI_AOC_TIME_SCALE_DAY;
}
}
| static int sig_pri_attempt_transfer | ( | struct sig_pri_span * | pri, |
| q931_call * | call_1_pri, | ||
| int | call_1_held, | ||
| q931_call * | call_2_pri, | ||
| int | call_2_held, | ||
| xfer_rsp_callback | rsp_callback, | ||
| void * | data | ||
| ) | [static] |
Definition at line 2002 of file sig_pri.c.
References ast_bridged_channel(), ast_channel_transfer_masquerade(), ast_channel_unlock, ast_mutex_lock, ast_mutex_unlock, ast_verb, sig_pri_span::lock, sig_pri_chan::owner, pri_find_pri_call(), sig_pri_span::pvts, sig_pri_lock_owner(), sig_pri_lock_private(), and sig_pri_unlock_private().
Referenced by pri_dchannel(), and sig_pri_handle_subcmds().
{
struct attempt_xfer_call {
q931_call *pri;
struct ast_channel *ast;
int held;
int chanpos;
};
int retval;
struct ast_channel *transferee;
struct attempt_xfer_call *call_1;
struct attempt_xfer_call *call_2;
struct attempt_xfer_call *swap_call;
struct attempt_xfer_call c1;
struct attempt_xfer_call c2;
c1.pri = call_1_pri;
c1.held = call_1_held;
call_1 = &c1;
c2.pri = call_2_pri;
c2.held = call_2_held;
call_2 = &c2;
call_1->chanpos = pri_find_pri_call(pri, call_1->pri);
call_2->chanpos = pri_find_pri_call(pri, call_2->pri);
if (call_1->chanpos < 0 || call_2->chanpos < 0) {
/* Calls not found in span control. */
if (rsp_callback) {
/* Transfer failed. */
rsp_callback(data, 0);
}
return -1;
}
/* Attempt to make transferee and target consistent. */
if (!call_1->held && call_2->held) {
/*
* Swap call_1 and call_2 to make call_1 the transferee(held call)
* and call_2 the target(active call).
*/
swap_call = call_1;
call_1 = call_2;
call_2 = swap_call;
}
/* Deadlock avoidance is attempted. */
sig_pri_lock_private(pri->pvts[call_1->chanpos]);
sig_pri_lock_owner(pri, call_1->chanpos);
sig_pri_lock_private(pri->pvts[call_2->chanpos]);
sig_pri_lock_owner(pri, call_2->chanpos);
call_1->ast = pri->pvts[call_1->chanpos]->owner;
call_2->ast = pri->pvts[call_2->chanpos]->owner;
if (!call_1->ast || !call_2->ast) {
/* At least one owner is not present. */
if (call_1->ast) {
ast_channel_unlock(call_1->ast);
}
if (call_2->ast) {
ast_channel_unlock(call_2->ast);
}
sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
if (rsp_callback) {
/* Transfer failed. */
rsp_callback(data, 0);
}
return -1;
}
for (;;) {
transferee = ast_bridged_channel(call_1->ast);
if (transferee) {
break;
}
/* Try masquerading the other way. */
swap_call = call_1;
call_1 = call_2;
call_2 = swap_call;
transferee = ast_bridged_channel(call_1->ast);
if (transferee) {
break;
}
/* Could not transfer. Neither call is bridged. */
ast_channel_unlock(call_1->ast);
ast_channel_unlock(call_2->ast);
sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
if (rsp_callback) {
/* Transfer failed. */
rsp_callback(data, 0);
}
return -1;
}
ast_verb(3, "TRANSFERRING %s to %s\n", call_1->ast->name, call_2->ast->name);
/*
* Setup transfer masquerade.
*
* Note: There is an extremely nasty deadlock avoidance issue
* with ast_channel_transfer_masquerade(). Deadlock may be possible if
* the channels involved are proxies (chan_agent channels) and
* it is called with locks. Unfortunately, there is no simple
* or even merely difficult way to guarantee deadlock avoidance
* and still be able to send an ECT success response without the
* possibility of the bridged channel hanging up on us.
*/
ast_mutex_unlock(&pri->lock);
retval = ast_channel_transfer_masquerade(
call_2->ast,
&call_2->ast->connected,
call_2->held,
transferee,
&call_1->ast->connected,
call_1->held);
/* Reacquire the pri->lock to hold off completion of the transfer masquerade. */
ast_mutex_lock(&pri->lock);
ast_channel_unlock(call_1->ast);
ast_channel_unlock(call_2->ast);
sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
if (rsp_callback) {
/*
* Report transfer status.
*
* Must do the callback before the masquerade completes to ensure
* that the protocol message goes out before the call leg is
* disconnected.
*/
rsp_callback(data, retval ? 0 : 1);
}
return retval;
}
| int sig_pri_available | ( | struct sig_pri_chan ** | pvt, |
| int | is_specific_channel | ||
| ) |
Definition at line 6779 of file sig_pri.c.
References HAVE_PRI_CALL_WAITING, sig_pri_span::num_call_waiting_calls, sig_pri_chan::pri, sig_pri_available_check(), and sig_pri_cw_available().
Referenced by available().
{
struct sig_pri_chan *p = *pvt;
if (!p->pri) {
/* Something is wrong here. A PRI channel without the pri pointer? */
return 0;
}
if (
#if defined(HAVE_PRI_CALL_WAITING)
/*
* Only do call waiting calls if we have any
* call waiting call outstanding. We do not
* want new calls to steal a B channel
* freed for an earlier call waiting call.
*/
!p->pri->num_call_waiting_calls &&
#endif /* defined(HAVE_PRI_CALL_WAITING) */
sig_pri_available_check(p)) {
return 1;
}
#if defined(HAVE_PRI_CALL_WAITING)
if (!is_specific_channel) {
struct sig_pri_chan *cw;
cw = sig_pri_cw_available(p->pri);
if (cw) {
/* We have a call waiting interface to use instead. */
*pvt = cw;
return 1;
}
}
#endif /* defined(HAVE_PRI_CALL_WAITING) */
return 0;
}
| static int sig_pri_available_check | ( | struct sig_pri_chan * | pvt | ) | [static] |
Definition at line 6714 of file sig_pri.c.
References sig_pri_chan::call, sig_pri_chan::inalarm, sig_pri_chan::no_b_channel, sig_pri_chan::owner, sig_pri_chan::resetting, and sig_pri_chan::service_status.
Referenced by sig_pri_available(), and sig_pri_cw_available().
{
/*
* If no owner, interface has a B channel, not resetting, not already with call,
* not in alarm, and in-service then available.
*/
if (!pvt->owner && !pvt->no_b_channel && !pvt->resetting && !pvt->call
&& !pvt->inalarm) {
#if defined(HAVE_PRI_SERVICE_MESSAGES)
if (pvt->service_status) {
return 0;
}
#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
return 1;
}
return 0;
}
| int sig_pri_call | ( | struct sig_pri_chan * | p, |
| struct ast_channel * | ast, | ||
| char * | rdest, | ||
| int | timeout, | ||
| int | layer1 | ||
| ) |
Definition at line 6036 of file sig_pri.c.
References ast_channel::_state, ao2_ref, sig_pri_span::append_msn_to_user_tag, args, AST_APP_ARG, ast_app_parse_options(), ast_assert, ast_cc_get_monitor_by_recall_core_id(), ast_cc_is_recall(), ast_channel_get_device_name(), AST_CHANNEL_NAME, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_free, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_party_subaddress_init(), ast_setstate(), AST_STATE_DIALING, AST_STATE_DOWN, AST_STATE_RESERVED, ast_strdup, ast_strlen_zero(), ast_test_flag, ast_transfercapability2str(), ast_verb, sig_pri_chan::call, ast_channel::caller, sig_pri_cc_monitor_instance::cc_id, sig_pri_chan::channel, ast_channel::connected, sig_pri_chan::dialdest, sig_pri_span::dialplan, dialplan2str(), sig_pri_chan::digital, ext, sig_pri_span::facilityenable, sig_pri_chan::hidecallerid, sig_pri_chan::hidecalleridname, ast_party_caller::id, ast_party_connected_line::id, sig_pri_span::initial_user_tag, sig_pri_span::internationalprefix, sig_pri_chan::is_call_waiting, IS_DIGITAL, sig_pri_span::localdialplan, LOG_DEBUG, LOG_ERROR, LOG_WARNING, monitor, ast_channel::name, ast_party_id::name, sig_pri_span::nationalprefix, sig_pri_span::nodetype, ast_party_id::number, ast_party_subaddress::odd_even_indicator, OPT_AOC_REQUEST, OPT_ARG_AOC_REQUEST, OPT_ARG_ARRAY_SIZE, OPT_ARG_KEYPAD, OPT_KEYPAD, OPT_REVERSE_CHARGE, sig_pri_chan::outgoing, sig_pri_chan::owner, pbx_builtin_getvar_helper(), ast_party_number::presentation, sig_pri_cc_monitor_instance::pri, sig_pri_span::pri, sig_pri_chan::pri, pri_grab(), pri_rel(), PRI_TRANS_CAP_DIGITAL, sig_pri_chan::priexclusive, ast_cc_monitor::private_data, PVT_TO_CHANNEL(), S_COR, sig_pri_call_opts, sig_pri_cc_type_name, sig_pri_party_subaddress_from_ast(), sig_pri_redirecting_update(), sig_pri_set_dialing(), sig_pri_set_digital(), ast_party_subaddress::str, ast_party_number::str, ast_party_name::str, sig_pri_chan::stripmsd, ast_party_id::subaddress, ast_party_id::tag, ast_channel::transfercapability, ast_party_subaddress::type, sig_pri_chan::use_callingpres, sig_pri_chan::user_tag, ast_party_subaddress::valid, ast_party_number::valid, and ast_party_name::valid.
Referenced by dahdi_call().
{
char dest[256]; /* must be same length as p->dialdest */
struct ast_party_subaddress dialed_subaddress; /* Called subaddress */
struct pri_sr *sr;
char *c, *l, *n, *s;
#ifdef SUPPORT_USERUSER
const char *useruser;
#endif
int core_id;
int pridialplan;
int dp_strip;
int prilocaldialplan;
int ldp_strip;
int exclusive;
#if defined(HAVE_PRI_SETUP_KEYPAD)
const char *keypad;
#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(group); /* channel/group token */
AST_APP_ARG(ext); /* extension token */
AST_APP_ARG(opts); /* options token */
AST_APP_ARG(other); /* Any remining unused arguments */
);
struct ast_flags opts;
char *opt_args[OPT_ARG_ARRAY_SIZE];
ast_log(LOG_DEBUG, "CALLER NAME: %s NUM: %s\n",
S_COR(ast->connected.id.name.valid, ast->connected.id.name.str, ""),
S_COR(ast->connected.id.number.valid, ast->connected.id.number.str, ""));
if (!p->pri) {
ast_log(LOG_ERROR, "Could not find pri on channel %d\n", p->channel);
return -1;
}
if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
ast_log(LOG_WARNING, "sig_pri_call called on %s, neither down nor reserved\n", ast->name);
return -1;
}
p->dialdest[0] = '\0';
p->outgoing = 1;
ast_copy_string(dest, rdest, sizeof(dest));
AST_NONSTANDARD_APP_ARGS(args, dest, '/');
if (ast_app_parse_options(sig_pri_call_opts, &opts, opt_args, args.opts)) {
/* General invalid option syntax. */
return -1;
}
c = args.ext;
if (!c) {
c = "";
}
/* setup dialed_subaddress if found */
ast_party_subaddress_init(&dialed_subaddress);
s = strchr(c, ':');
if (s) {
*s = '\0';
s++;
/* prefix */
/* 'n' = NSAP */
/* 'U' = odd, 'u'= even */
/* Default = NSAP */
switch (*s) {
case 'U':
dialed_subaddress.odd_even_indicator = 1;
/* fall through */
case 'u':
s++;
dialed_subaddress.type = 2;
break;
case 'N':
case 'n':
s++;
/* default already covered with ast_party_subaddress_init */
break;
}
dialed_subaddress.str = s;
dialed_subaddress.valid = 1;
s = NULL;
}
l = NULL;
n = NULL;
if (!p->hidecallerid) {
if (ast->connected.id.number.valid) {
/* If we get to the end of this loop without breaking, there's no
* calleridnum. This is done instead of testing for "unknown" or
* the thousands of other ways that the calleridnum could be
* invalid. */
for (l = ast->connected.id.number.str; l && *l; l++) {
if (strchr("0123456789", *l)) {
l = ast->connected.id.number.str;
break;
}
}
} else {
l = NULL;
}
if (!p->hidecalleridname) {
n = ast->connected.id.name.valid ? ast->connected.id.name.str : NULL;
}
}
if (strlen(c) < p->stripmsd) {
ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
return -1;
}
if (pri_grab(p, p->pri)) {
ast_log(LOG_WARNING, "Failed to grab PRI!\n");
return -1;
}
if (!(p->call = pri_new_call(p->pri->pri))) {
ast_log(LOG_WARNING, "Unable to create call on channel %d\n", p->channel);
pri_rel(p->pri);
return -1;
}
if (!(sr = pri_sr_new())) {
ast_log(LOG_WARNING, "Failed to allocate setup request channel %d\n", p->channel);
pri_destroycall(p->pri->pri, p->call);
p->call = NULL;
pri_rel(p->pri);
return -1;
}
sig_pri_set_digital(p, IS_DIGITAL(ast->transfercapability)); /* push up to parent for EC */
#if defined(HAVE_PRI_CALL_WAITING)
if (p->is_call_waiting) {
/*
* Indicate that this is a call waiting call.
* i.e., Normal call but with no B channel.
*/
pri_sr_set_channel(sr, 0, 0, 1);
} else
#endif /* defined(HAVE_PRI_CALL_WAITING) */
{
/* Should the picked channel be used exclusively? */
if (p->priexclusive || p->pri->nodetype == PRI_NETWORK) {
exclusive = 1;
} else {
exclusive = 0;
}
pri_sr_set_channel(sr, PVT_TO_CHANNEL(p), exclusive, 1);
}
pri_sr_set_bearer(sr, p->digital ? PRI_TRANS_CAP_DIGITAL : ast->transfercapability,
(p->digital ? -1 : layer1));
if (p->pri->facilityenable)
pri_facility_enable(p->pri->pri);
ast_verb(3, "Requested transfer capability: 0x%.2x - %s\n", ast->transfercapability, ast_transfercapability2str(ast->transfercapability));
dp_strip = 0;
pridialplan = p->pri->dialplan - 1;
if (pridialplan == -2 || pridialplan == -3) { /* compute dynamically */
if (strncmp(c + p->stripmsd, p->pri->internationalprefix, strlen(p->pri->internationalprefix)) == 0) {
if (pridialplan == -2) {
dp_strip = strlen(p->pri->internationalprefix);
}
pridialplan = PRI_INTERNATIONAL_ISDN;
} else if (strncmp(c + p->stripmsd, p->pri->nationalprefix, strlen(p->pri->nationalprefix)) == 0) {
if (pridialplan == -2) {
dp_strip = strlen(p->pri->nationalprefix);
}
pridialplan = PRI_NATIONAL_ISDN;
} else {
pridialplan = PRI_LOCAL_ISDN;
}
}
while (c[p->stripmsd] > '9' && c[p->stripmsd] != '*' && c[p->stripmsd] != '#') {
switch (c[p->stripmsd]) {
case 'U':
pridialplan = (PRI_TON_UNKNOWN << 4) | (pridialplan & 0xf);
break;
case 'I':
pridialplan = (PRI_TON_INTERNATIONAL << 4) | (pridialplan & 0xf);
break;
case 'N':
pridialplan = (PRI_TON_NATIONAL << 4) | (pridialplan & 0xf);
break;
case 'L':
pridialplan = (PRI_TON_NET_SPECIFIC << 4) | (pridialplan & 0xf);
break;
case 'S':
pridialplan = (PRI_TON_SUBSCRIBER << 4) | (pridialplan & 0xf);
break;
case 'V':
pridialplan = (PRI_TON_ABBREVIATED << 4) | (pridialplan & 0xf);
break;
case 'R':
pridialplan = (PRI_TON_RESERVED << 4) | (pridialplan & 0xf);
break;
case 'u':
pridialplan = PRI_NPI_UNKNOWN | (pridialplan & 0xf0);
break;
case 'e':
pridialplan = PRI_NPI_E163_E164 | (pridialplan & 0xf0);
break;
case 'x':
pridialplan = PRI_NPI_X121 | (pridialplan & 0xf0);
break;
case 'f':
pridialplan = PRI_NPI_F69 | (pridialplan & 0xf0);
break;
case 'n':
pridialplan = PRI_NPI_NATIONAL | (pridialplan & 0xf0);
break;
case 'p':
pridialplan = PRI_NPI_PRIVATE | (pridialplan & 0xf0);
break;
case 'r':
pridialplan = PRI_NPI_RESERVED | (pridialplan & 0xf0);
break;
default:
if (isalpha(c[p->stripmsd])) {
ast_log(LOG_WARNING, "Unrecognized pridialplan %s modifier: %c\n",
c[p->stripmsd] > 'Z' ? "NPI" : "TON", c[p->stripmsd]);
}
break;
}
c++;
}
#if defined(HAVE_PRI_SETUP_KEYPAD)
if (ast_test_flag(&opts, OPT_KEYPAD)
&& !ast_strlen_zero(opt_args[OPT_ARG_KEYPAD])) {
/* We have a keypad facility digits option with digits. */
keypad = opt_args[OPT_ARG_KEYPAD];
pri_sr_set_keypad_digits(sr, keypad);
} else {
keypad = NULL;
}
if (!keypad || !ast_strlen_zero(c + p->stripmsd + dp_strip))
#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
{
pri_sr_set_called(sr, c + p->stripmsd + dp_strip, pridialplan, s ? 1 : 0);
}
#if defined(HAVE_PRI_SUBADDR)
if (dialed_subaddress.valid) {
struct pri_party_subaddress subaddress;
memset(&subaddress, 0, sizeof(subaddress));
sig_pri_party_subaddress_from_ast(&subaddress, &dialed_subaddress);
pri_sr_set_called_subaddress(sr, &subaddress);
}
#endif /* defined(HAVE_PRI_SUBADDR) */
#if defined(HAVE_PRI_REVERSE_CHARGE)
if (ast_test_flag(&opts, OPT_REVERSE_CHARGE)) {
pri_sr_set_reversecharge(sr, PRI_REVERSECHARGE_REQUESTED);
}
#endif /* defined(HAVE_PRI_REVERSE_CHARGE) */
#if defined(HAVE_PRI_AOC_EVENTS)
if (ast_test_flag(&opts, OPT_AOC_REQUEST)
&& !ast_strlen_zero(opt_args[OPT_ARG_AOC_REQUEST])) {
if (strchr(opt_args[OPT_ARG_AOC_REQUEST], 's')) {
pri_sr_set_aoc_charging_request(sr, PRI_AOC_REQUEST_S);
}
if (strchr(opt_args[OPT_ARG_AOC_REQUEST], 'd')) {
pri_sr_set_aoc_charging_request(sr, PRI_AOC_REQUEST_D);
}
if (strchr(opt_args[OPT_ARG_AOC_REQUEST], 'e')) {
pri_sr_set_aoc_charging_request(sr, PRI_AOC_REQUEST_E);
}
}
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
/* Setup the user tag for party id's from this device for this call. */
if (p->pri->append_msn_to_user_tag) {
snprintf(p->user_tag, sizeof(p->user_tag), "%s_%s", p->pri->initial_user_tag,
p->pri->nodetype == PRI_NETWORK
? c + p->stripmsd + dp_strip
: S_COR(ast->connected.id.number.valid,
ast->connected.id.number.str, ""));
} else {
ast_copy_string(p->user_tag, p->pri->initial_user_tag, sizeof(p->user_tag));
}
/*
* Replace the caller id tag from the channel creation
* with the actual tag value.
*/
ast_free(ast->caller.id.tag);
ast->caller.id.tag = ast_strdup(p->user_tag);
ldp_strip = 0;
prilocaldialplan = p->pri->localdialplan - 1;
if ((l != NULL) && (prilocaldialplan == -2 || prilocaldialplan == -3)) { /* compute dynamically */
if (strncmp(l, p->pri->internationalprefix, strlen(p->pri->internationalprefix)) == 0) {
if (prilocaldialplan == -2) {
ldp_strip = strlen(p->pri->internationalprefix);
}
prilocaldialplan = PRI_INTERNATIONAL_ISDN;
} else if (strncmp(l, p->pri->nationalprefix, strlen(p->pri->nationalprefix)) == 0) {
if (prilocaldialplan == -2) {
ldp_strip = strlen(p->pri->nationalprefix);
}
prilocaldialplan = PRI_NATIONAL_ISDN;
} else {
prilocaldialplan = PRI_LOCAL_ISDN;
}
}
if (l != NULL) {
while (*l > '9' && *l != '*' && *l != '#') {
switch (*l) {
case 'U':
prilocaldialplan = (PRI_TON_UNKNOWN << 4) | (prilocaldialplan & 0xf);
break;
case 'I':
prilocaldialplan = (PRI_TON_INTERNATIONAL << 4) | (prilocaldialplan & 0xf);
break;
case 'N':
prilocaldialplan = (PRI_TON_NATIONAL << 4) | (prilocaldialplan & 0xf);
break;
case 'L':
prilocaldialplan = (PRI_TON_NET_SPECIFIC << 4) | (prilocaldialplan & 0xf);
break;
case 'S':
prilocaldialplan = (PRI_TON_SUBSCRIBER << 4) | (prilocaldialplan & 0xf);
break;
case 'V':
prilocaldialplan = (PRI_TON_ABBREVIATED << 4) | (prilocaldialplan & 0xf);
break;
case 'R':
prilocaldialplan = (PRI_TON_RESERVED << 4) | (prilocaldialplan & 0xf);
break;
case 'u':
prilocaldialplan = PRI_NPI_UNKNOWN | (prilocaldialplan & 0xf0);
break;
case 'e':
prilocaldialplan = PRI_NPI_E163_E164 | (prilocaldialplan & 0xf0);
break;
case 'x':
prilocaldialplan = PRI_NPI_X121 | (prilocaldialplan & 0xf0);
break;
case 'f':
prilocaldialplan = PRI_NPI_F69 | (prilocaldialplan & 0xf0);
break;
case 'n':
prilocaldialplan = PRI_NPI_NATIONAL | (prilocaldialplan & 0xf0);
break;
case 'p':
prilocaldialplan = PRI_NPI_PRIVATE | (prilocaldialplan & 0xf0);
break;
case 'r':
prilocaldialplan = PRI_NPI_RESERVED | (prilocaldialplan & 0xf0);
break;
default:
if (isalpha(*l)) {
ast_log(LOG_WARNING,
"Unrecognized prilocaldialplan %s modifier: %c\n",
*l > 'Z' ? "NPI" : "TON", *l);
}
break;
}
l++;
}
}
pri_sr_set_caller(sr, l ? (l + ldp_strip) : NULL, n, prilocaldialplan,
p->use_callingpres ? ast->connected.id.number.presentation : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE));
#if defined(HAVE_PRI_SUBADDR)
if (ast->connected.id.subaddress.valid) {
struct pri_party_subaddress subaddress;
memset(&subaddress, 0, sizeof(subaddress));
sig_pri_party_subaddress_from_ast(&subaddress, &ast->connected.id.subaddress);
pri_sr_set_caller_subaddress(sr, &subaddress);
}
#endif /* defined(HAVE_PRI_SUBADDR) */
sig_pri_redirecting_update(p, ast);
#ifdef SUPPORT_USERUSER
/* User-user info */
useruser = pbx_builtin_getvar_helper(p->owner, "USERUSERINFO");
if (useruser)
pri_sr_set_useruser(sr, useruser);
#endif
#if defined(HAVE_PRI_CCSS)
if (ast_cc_is_recall(ast, &core_id, sig_pri_cc_type_name)) {
struct ast_cc_monitor *monitor;
char device_name[AST_CHANNEL_NAME];
/* This is a CC recall call. */
ast_channel_get_device_name(ast, device_name, sizeof(device_name));
monitor = ast_cc_get_monitor_by_recall_core_id(core_id, device_name);
if (monitor) {
struct sig_pri_cc_monitor_instance *instance;
instance = monitor->private_data;
/* If this fails then we have monitor instance ambiguity. */
ast_assert(p->pri == instance->pri);
if (pri_cc_call(p->pri->pri, instance->cc_id, p->call, sr)) {
/* The CC recall call failed for some reason. */
ast_log(LOG_WARNING, "Unable to setup CC recall call to device %s\n",
device_name);
ao2_ref(monitor, -1);
pri_rel(p->pri);
pri_sr_free(sr);
return -1;
}
ao2_ref(monitor, -1);
} else {
core_id = -1;
}
} else
#endif /* defined(HAVE_PRI_CCSS) */
{
core_id = -1;
}
if (core_id == -1 && pri_setup(p->pri->pri, p->call, sr)) {
ast_log(LOG_WARNING, "Unable to setup call to %s (using %s)\n",
c + p->stripmsd + dp_strip, dialplan2str(p->pri->dialplan));
pri_rel(p->pri);
pri_sr_free(sr);
return -1;
}
pri_sr_free(sr);
ast_setstate(ast, AST_STATE_DIALING);
sig_pri_set_dialing(p, 1);
pri_rel(p->pri);
return 0;
}
| int sig_pri_cc_agent_callee_available | ( | struct ast_cc_agent * | agent | ) |
Alert the caller that it is time to try recalling.
| agent | CC core agent control. |
The core will call this function when it receives notice that a monitored party has become available.
The agent's job is to send a message to the caller to notify it of such a change. If the agent is able to discern that the caller is currently unavailable, then the agent should react by calling the ast_cc_caller_unavailable function.
| 0 | on success. |
| -1 | on error. |
Definition at line 7642 of file sig_pri.c.
References ast_mutex_lock, ast_mutex_unlock, sig_pri_cc_agent_prv::cc_id, sig_pri_span::lock, sig_pri_span::pri, sig_pri_cc_agent_prv::pri, and ast_cc_agent::private_data.
{
struct sig_pri_cc_agent_prv *cc_pvt;
cc_pvt = agent->private_data;
ast_mutex_lock(&cc_pvt->pri->lock);
pri_cc_remote_user_free(cc_pvt->pri->pri, cc_pvt->cc_id);
ast_mutex_unlock(&cc_pvt->pri->lock);
return 0;
}
| static int sig_pri_cc_agent_cmp_cc_id | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 2158 of file sig_pri.c.
References sig_pri_cc_agent_prv::cc_id, CMP_MATCH, CMP_STOP, sig_pri_cc_agent_prv::pri, and ast_cc_agent::private_data.
Referenced by sig_pri_find_cc_agent_by_cc_id().
{
struct ast_cc_agent *agent_1 = obj;
struct sig_pri_cc_agent_prv *agent_prv_1 = agent_1->private_data;
struct sig_pri_cc_agent_prv *agent_prv_2 = arg;
return (agent_prv_1 && agent_prv_1->pri == agent_prv_2->pri
&& agent_prv_1->cc_id == agent_prv_2->cc_id) ? CMP_MATCH | CMP_STOP : 0;
}
| void sig_pri_cc_agent_destructor | ( | struct ast_cc_agent * | agent | ) |
Destroy private data on the agent.
| agent | CC core agent control. |
The core will call this function upon completion or failure of CC.
Definition at line 7671 of file sig_pri.c.
References ast_free, ast_mutex_lock, ast_mutex_unlock, sig_pri_cc_agent_prv::cc_id, sig_pri_cc_agent_prv::cc_request_response_pending, sig_pri_span::lock, sig_pri_span::pri, sig_pri_cc_agent_prv::pri, and ast_cc_agent::private_data.
Referenced by dahdi_pri_cc_agent_destructor().
{
struct sig_pri_cc_agent_prv *cc_pvt;
int res;
cc_pvt = agent->private_data;
if (!cc_pvt) {
/* The agent constructor probably failed. */
return;
}
ast_mutex_lock(&cc_pvt->pri->lock);
res = -1;
if (cc_pvt->cc_request_response_pending) {
res = pri_cc_req_rsp(cc_pvt->pri->pri, cc_pvt->cc_id, 2/* short_term_denial */);
}
if (res) {
pri_cc_cancel(cc_pvt->pri->pri, cc_pvt->cc_id);
}
ast_mutex_unlock(&cc_pvt->pri->lock);
ast_free(cc_pvt);
}
| int sig_pri_cc_agent_init | ( | struct ast_cc_agent * | agent, |
| struct sig_pri_chan * | pvt_chan | ||
| ) |
PRI CC agent initialization.
| agent | CC core agent control. |
| pvt_chan | Original channel the agent will attempt to recall. |
This callback is called when the CC core is initialized. Agents should allocate any private data necessary for the call and assign it to the private_data on the agent. Additionally, if any ast_cc_agent_flags are pertinent to the specific agent type, they should be set in this function as well.
| 0 | on success. |
| -1 | on error. |
Definition at line 7391 of file sig_pri.c.
References ast_calloc, ast_free, ast_mutex_lock, ast_mutex_unlock, sig_pri_chan::call, sig_pri_cc_agent_prv::cc_id, sig_pri_span::lock, sig_pri_span::pri, sig_pri_cc_agent_prv::pri, sig_pri_chan::pri, and ast_cc_agent::private_data.
Referenced by dahdi_pri_cc_agent_init().
{
struct sig_pri_cc_agent_prv *cc_pvt;
cc_pvt = ast_calloc(1, sizeof(*cc_pvt));
if (!cc_pvt) {
return -1;
}
ast_mutex_lock(&pvt_chan->pri->lock);
cc_pvt->pri = pvt_chan->pri;
cc_pvt->cc_id = pri_cc_available(pvt_chan->pri->pri, pvt_chan->call);
ast_mutex_unlock(&pvt_chan->pri->lock);
if (cc_pvt->cc_id == -1) {
ast_free(cc_pvt);
return -1;
}
agent->private_data = cc_pvt;
return 0;
}
| int sig_pri_cc_agent_party_b_free | ( | struct ast_cc_agent * | agent | ) |
Let the caller know that the callee has become free but that the caller cannot attempt to call back because he is either busy or there is congestion on his line.
| agent | CC core agent control. |
This is something that really only affects a scenario where a phone places a call over ISDN PTMP to Asterisk, who then connects over PTMP again to the ISDN network. For most agent types, there is no need to implement this callback at all because they don't really need to actually do anything in this situation. If you're having trouble understanding what the purpose of this callback is, then you can be safe simply not implementing it.
| 0 | on success. |
| -1 | on error. |
Definition at line 7586 of file sig_pri.c.
References ast_mutex_lock, ast_mutex_unlock, sig_pri_cc_agent_prv::cc_id, sig_pri_span::lock, sig_pri_span::pri, sig_pri_cc_agent_prv::pri, and ast_cc_agent::private_data.
{
struct sig_pri_cc_agent_prv *cc_pvt;
cc_pvt = agent->private_data;
ast_mutex_lock(&cc_pvt->pri->lock);
pri_cc_b_free(cc_pvt->pri->pri, cc_pvt->cc_id);
ast_mutex_unlock(&cc_pvt->pri->lock);
return 0;
}
| void sig_pri_cc_agent_req_ack | ( | struct ast_cc_agent * | agent | ) |
Acknowledge CC request.
| agent | CC core agent control. |
When the core receives knowledge that a called party has accepted a CC request, it will call this callback.
The duty of this is to accept a CC request from the caller by acknowledging receipt of that request.
Definition at line 7480 of file sig_pri.c.
References ast_cc_failed(), ast_mutex_lock, ast_mutex_unlock, sig_pri_cc_agent_prv::cc_id, sig_pri_cc_agent_prv::cc_request_response_pending, ast_cc_agent::core_id, sig_pri_span::lock, sig_pri_span::pri, sig_pri_cc_agent_prv::pri, ast_cc_agent::private_data, and sig_pri_cc_type_name.
{
struct sig_pri_cc_agent_prv *cc_pvt;
int res;
cc_pvt = agent->private_data;
ast_mutex_lock(&cc_pvt->pri->lock);
if (cc_pvt->cc_request_response_pending) {
cc_pvt->cc_request_response_pending = 0;
res = pri_cc_req_rsp(cc_pvt->pri->pri, cc_pvt->cc_id, 0/* success */);
} else {
res = 0;
}
ast_mutex_unlock(&cc_pvt->pri->lock);
if (res) {
ast_cc_failed(agent->core_id, "%s agent failed to send the CC request ack.",
sig_pri_cc_type_name);
}
}
| int sig_pri_cc_agent_start_monitoring | ( | struct ast_cc_agent * | agent | ) |
Begin monitoring a busy device.
| agent | CC core agent control. |
The core will call this callback if the callee becomes available but the caller has reported that he is busy. The agent should begin monitoring the caller's device. When the caller becomes available again, the agent should call ast_cc_agent_caller_available.
| 0 | on success. |
| -1 | on error. |
Definition at line 7615 of file sig_pri.c.
{
/* libpri already knows when and how it needs to monitor Party A. */
return 0;
}
| int sig_pri_cc_agent_start_offer_timer | ( | struct ast_cc_agent * | agent | ) |
Start the offer timer.
| agent | CC core agent control. |
This is called by the core when the caller hangs up after a call for which CC may be requested. The agent should begin the timer as configured.
The primary reason why this functionality is left to the specific agent implementations is due to the differing use of schedulers throughout the code. Some channel drivers may already have a scheduler context they wish to use, and amongst those, some may use the ast_sched API while others may use the ast_sched_thread API, which are incompatible.
| 0 | on success. |
| -1 | on error. |
Definition at line 7435 of file sig_pri.c.
{
/* libpri maintains it's own offer timer in the form of T_RETENTION. */
return 0;
}
| int sig_pri_cc_agent_status_req | ( | struct ast_cc_agent * | agent | ) |
Request the status of the agent's device.
| agent | CC core agent control. |
Asynchronous request for the status of any caller which may be a valid caller for the CC transaction. Status responses should be made using the ast_cc_status_response function.
| 0 | on success. |
| -1 | on error. |
Definition at line 7517 of file sig_pri.c.
References ast_mutex_lock, ast_mutex_unlock, sig_pri_cc_agent_prv::cc_id, sig_pri_span::lock, sig_pri_span::pri, sig_pri_cc_agent_prv::pri, and ast_cc_agent::private_data.
{
struct sig_pri_cc_agent_prv *cc_pvt;
cc_pvt = agent->private_data;
ast_mutex_lock(&cc_pvt->pri->lock);
pri_cc_status_req(cc_pvt->pri->pri, cc_pvt->cc_id);
ast_mutex_unlock(&cc_pvt->pri->lock);
return 0;
}
| int sig_pri_cc_agent_stop_offer_timer | ( | struct ast_cc_agent * | agent | ) |
Stop the offer timer.
| agent | CC core agent control. |
This callback is called by the CC core when the caller has requested CC.
| 0 | on success. |
| -1 | on error. |
Definition at line 7456 of file sig_pri.c.
{
/* libpri maintains it's own offer timer in the form of T_RETENTION. */
return 0;
}
| int sig_pri_cc_agent_stop_ringing | ( | struct ast_cc_agent * | agent | ) |
Request for an agent's phone to stop ringing.
| agent | CC core agent control. |
The usefulness of this is quite limited. The only specific known case for this is if Asterisk requests CC over an ISDN PTMP link as the TE side. If other phones are in the same recall group as the Asterisk server, and one of those phones picks up the recall notice, then Asterisk will receive a "stop ringing" notification from the NT side of the PTMP link. This indication needs to be passed to the phone on the other side of the Asterisk server which originally placed the call so that it will stop ringing. Since the phone may be of any type, it is necessary to have a callback that the core can know about.
| 0 | on success. |
| -1 | on error. |
Definition at line 7552 of file sig_pri.c.
References ast_mutex_lock, ast_mutex_unlock, sig_pri_cc_agent_prv::cc_id, sig_pri_span::lock, sig_pri_span::pri, sig_pri_cc_agent_prv::pri, and ast_cc_agent::private_data.
{
struct sig_pri_cc_agent_prv *cc_pvt;
cc_pvt = agent->private_data;
ast_mutex_lock(&cc_pvt->pri->lock);
pri_cc_stop_alerting(cc_pvt->pri->pri, cc_pvt->cc_id);
ast_mutex_unlock(&cc_pvt->pri->lock);
return 0;
}
| static int sig_pri_cc_available | ( | struct sig_pri_span * | pri, |
| int | chanpos, | ||
| long | cc_id, | ||
| enum ast_cc_service_type | service | ||
| ) | [static] |
Definition at line 2334 of file sig_pri.c.
References ao2_ref, ao2_unlink, AST_CC_GENERIC_MONITOR_TYPE, ast_cc_get_current_core_id(), AST_CC_MONITOR_ALWAYS, AST_CC_MONITOR_GENERIC, AST_CC_MONITOR_NATIVE, AST_CC_MONITOR_NEVER, ast_channel_get_cc_config_params(), ast_channel_get_device_name(), AST_CHANNEL_NAME, ast_get_cc_monitor_policy(), ast_queue_cc_frame(), sig_pri_cc_monitor_instance::cc_id, sig_pri_cc_monitor_instance::core_id, monitor, sig_pri_chan::owner, sig_pri_span::pvts, sig_pri_cc_monitor_instance_init(), sig_pri_cc_type_name, sig_pri_get_orig_dialstring(), and sig_pri_make_cc_dialstring().
Referenced by sig_pri_handle_subcmds().
{
struct sig_pri_chan *pvt;
struct ast_cc_config_params *cc_params;
struct sig_pri_cc_monitor_instance *monitor;
enum ast_cc_monitor_policies monitor_policy;
int core_id;
int res;
char device_name[AST_CHANNEL_NAME];
char dialstring[AST_CHANNEL_NAME];
pvt = pri->pvts[chanpos];
core_id = ast_cc_get_current_core_id(pvt->owner);
if (core_id == -1) {
return -1;
}
cc_params = ast_channel_get_cc_config_params(pvt->owner);
if (!cc_params) {
return -1;
}
res = -1;
monitor_policy = ast_get_cc_monitor_policy(cc_params);
switch (monitor_policy) {
case AST_CC_MONITOR_NEVER:
/* CCSS is not enabled. */
break;
case AST_CC_MONITOR_NATIVE:
case AST_CC_MONITOR_ALWAYS:
/*
* If it is AST_CC_MONITOR_ALWAYS and native fails we will attempt the fallback
* later in the call to sig_pri_cc_generic_check().
*/
ast_channel_get_device_name(pvt->owner, device_name, sizeof(device_name));
sig_pri_make_cc_dialstring(pvt, dialstring, sizeof(dialstring));
monitor = sig_pri_cc_monitor_instance_init(core_id, pri, cc_id, device_name);
if (!monitor) {
break;
}
res = ast_queue_cc_frame(pvt->owner, sig_pri_cc_type_name, dialstring, service,
monitor);
if (res) {
monitor->cc_id = -1;
ao2_unlink(sig_pri_cc_monitors, monitor);
ao2_ref(monitor, -1);
}
break;
case AST_CC_MONITOR_GENERIC:
ast_queue_cc_frame(pvt->owner, AST_CC_GENERIC_MONITOR_TYPE,
sig_pri_get_orig_dialstring(pvt), service, NULL);
/* Say it failed to force caller to cancel native CC. */
break;
}
return res;
}
| static void sig_pri_cc_generic_check | ( | struct sig_pri_span * | pri, |
| int | chanpos, | ||
| enum ast_cc_service_type | service | ||
| ) | [static] |
Definition at line 2407 of file sig_pri.c.
References ao2_ref, AST_CC_GENERIC_MONITOR_TYPE, ast_cc_get_current_core_id(), ast_cc_get_monitor_by_recall_core_id(), AST_CC_MONITOR_ALWAYS, AST_CC_MONITOR_GENERIC, AST_CC_MONITOR_NATIVE, AST_CC_MONITOR_NEVER, ast_channel_get_cc_config_params(), ast_channel_get_device_name(), AST_CHANNEL_NAME, ast_channel_unlock, ast_get_cc_monitor_policy(), ast_queue_cc_frame(), ast_cc_monitor::core_id, monitor, sig_pri_span::nodetype, sig_pri_chan::outgoing, sig_pri_chan::owner, sig_pri_span::pvts, sig_pri_span::sig, SIG_BRI_PTMP, sig_pri_get_orig_dialstring(), and sig_pri_lock_owner().
Referenced by pri_dchannel().
{
struct ast_channel *owner;
struct ast_cc_config_params *cc_params;
#if defined(HAVE_PRI_CCSS)
struct ast_cc_monitor *monitor;
char device_name[AST_CHANNEL_NAME];
#endif /* defined(HAVE_PRI_CCSS) */
enum ast_cc_monitor_policies monitor_policy;
int core_id;
if (!pri->pvts[chanpos]->outgoing) {
/* This is not an outgoing call so it cannot be CC monitor. */
return;
}
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (!owner) {
return;
}
core_id = ast_cc_get_current_core_id(owner);
if (core_id == -1) {
/* No CC core setup */
goto done;
}
cc_params = ast_channel_get_cc_config_params(owner);
if (!cc_params) {
/* Could not get CC config parameters. */
goto done;
}
#if defined(HAVE_PRI_CCSS)
ast_channel_get_device_name(owner, device_name, sizeof(device_name));
monitor = ast_cc_get_monitor_by_recall_core_id(core_id, device_name);
if (monitor) {
/* CC monitor is already present so no need for generic CC. */
ao2_ref(monitor, -1);
goto done;
}
#endif /* defined(HAVE_PRI_CCSS) */
monitor_policy = ast_get_cc_monitor_policy(cc_params);
switch (monitor_policy) {
case AST_CC_MONITOR_NEVER:
/* CCSS is not enabled. */
break;
case AST_CC_MONITOR_NATIVE:
if (pri->sig == SIG_BRI_PTMP && pri->nodetype == PRI_NETWORK) {
/* Request generic CC monitor. */
ast_queue_cc_frame(owner, AST_CC_GENERIC_MONITOR_TYPE,
sig_pri_get_orig_dialstring(pri->pvts[chanpos]), service, NULL);
}
break;
case AST_CC_MONITOR_ALWAYS:
if (pri->sig == SIG_BRI_PTMP && pri->nodetype != PRI_NETWORK) {
/*
* Cannot monitor PTMP TE side since this is not defined.
* We are playing the roll of a phone in this case and
* a phone cannot monitor a party over the network without
* protocol help.
*/
break;
}
/*
* We are either falling back or this is a PTMP NT span.
* Request generic CC monitor.
*/
ast_queue_cc_frame(owner, AST_CC_GENERIC_MONITOR_TYPE,
sig_pri_get_orig_dialstring(pri->pvts[chanpos]), service, NULL);
break;
case AST_CC_MONITOR_GENERIC:
if (pri->sig == SIG_BRI_PTMP && pri->nodetype == PRI_NETWORK) {
/* Request generic CC monitor. */
ast_queue_cc_frame(owner, AST_CC_GENERIC_MONITOR_TYPE,
sig_pri_get_orig_dialstring(pri->pvts[chanpos]), service, NULL);
}
break;
}
done:
ast_channel_unlock(owner);
}
| static void sig_pri_cc_link_canceled | ( | struct sig_pri_span * | pri, |
| long | cc_id, | ||
| int | is_agent | ||
| ) | [static] |
Definition at line 2504 of file sig_pri.c.
References ao2_ref, ast_cc_failed(), ast_cc_monitor_failed(), sig_pri_cc_monitor_instance::cc_id, sig_pri_cc_monitor_instance::core_id, ast_cc_agent::core_id, monitor, sig_pri_cc_monitor_instance::name, sig_pri_cc_type_name, sig_pri_find_cc_agent_by_cc_id(), and sig_pri_find_cc_monitor_by_cc_id().
Referenced by sig_pri_handle_cis_subcmds(), and sig_pri_handle_subcmds().
{
if (is_agent) {
struct ast_cc_agent *agent;
agent = sig_pri_find_cc_agent_by_cc_id(pri, cc_id);
if (!agent) {
return;
}
ast_cc_failed(agent->core_id, "%s agent got canceled by link",
sig_pri_cc_type_name);
ao2_ref(agent, -1);
} else {
struct sig_pri_cc_monitor_instance *monitor;
monitor = sig_pri_find_cc_monitor_by_cc_id(pri, cc_id);
if (!monitor) {
return;
}
monitor->cc_id = -1;
ast_cc_monitor_failed(monitor->core_id, monitor->name,
"%s monitor got canceled by link", sig_pri_cc_type_name);
ao2_ref(monitor, -1);
}
}
| int sig_pri_cc_monitor_cancel_available_timer | ( | struct ast_cc_monitor * | monitor, |
| int * | sched_id | ||
| ) |
Cancel the running available timer.
| monitor | CC core monitor control. |
| sched_id | Available timer scheduler id to cancel. Will never be NULL for a device monitor. |
In most cases, this function will likely consist of just a call to AST_SCHED_DEL. It might have been possible to do this within the core, but unfortunately the mixture of sched_thread and sched usage in Asterisk prevents such usage.
| 0 | on success |
| -1 | on failure. |
Definition at line 7897 of file sig_pri.c.
{
/*
* libpri maintains it's own available timer as one of:
* T_CCBS2/T_CCBS5/T_CCBS6/QSIG_CCBS_T2
* T_CCNR2/T_CCNR5/T_CCNR6/QSIG_CCNR_T2
*/
return 0;
}
| static int sig_pri_cc_monitor_cmp_cc_id | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 2210 of file sig_pri.c.
References sig_pri_cc_monitor_instance::cc_id, CMP_MATCH, CMP_STOP, and sig_pri_cc_monitor_instance::pri.
Referenced by sig_pri_find_cc_monitor_by_cc_id().
{
struct sig_pri_cc_monitor_instance *monitor_1 = obj;
struct sig_pri_cc_monitor_instance *monitor_2 = arg;
return (monitor_1->pri == monitor_2->pri
&& monitor_1->cc_id == monitor_2->cc_id) ? CMP_MATCH | CMP_STOP : 0;
}
| void sig_pri_cc_monitor_destructor | ( | void * | monitor_pvt | ) |
Destroy PRI private data on the monitor.
| monitor_pvt | CC device monitor private data pointer. |
Implementers of this callback are responsible for destroying all heap-allocated data in the monitor's private_data pointer, including the private_data itself.
Definition at line 7920 of file sig_pri.c.
References ao2_ref, and ao2_unlink.
{
struct sig_pri_cc_monitor_instance *instance;
instance = monitor_pvt;
if (!instance) {
return;
}
ao2_unlink(sig_pri_cc_monitors, instance);
ao2_ref(instance, -1);
}
| static int sig_pri_cc_monitor_instance_cmp_fn | ( | void * | obj, |
| void * | arg, | ||
| int | flags | ||
| ) | [static] |
Definition at line 7725 of file sig_pri.c.
References CMP_MATCH, CMP_STOP, and sig_pri_cc_monitor_instance::core_id.
Referenced by sig_pri_load().
{
struct sig_pri_cc_monitor_instance *monitor_1 = obj;
struct sig_pri_cc_monitor_instance *monitor_2 = arg;
return monitor_1->core_id == monitor_2->core_id ? CMP_MATCH | CMP_STOP : 0;
}
| static void sig_pri_cc_monitor_instance_destroy | ( | void * | data | ) | [static] |
Definition at line 2258 of file sig_pri.c.
References ast_mutex_lock, ast_mutex_unlock, sig_pri_span::calls, sig_pri_cc_monitor_instance::cc_id, sig_pri_span::lock, sig_pri_callback::module_unref, sig_pri_span::pri, and sig_pri_cc_monitor_instance::pri.
Referenced by sig_pri_cc_monitor_instance_init().
{
struct sig_pri_cc_monitor_instance *monitor_instance = data;
if (monitor_instance->cc_id != -1) {
ast_mutex_lock(&monitor_instance->pri->lock);
pri_cc_cancel(monitor_instance->pri->pri, monitor_instance->cc_id);
ast_mutex_unlock(&monitor_instance->pri->lock);
}
monitor_instance->pri->calls->module_unref();
}
| static int sig_pri_cc_monitor_instance_hash_fn | ( | const void * | obj, |
| const int | flags | ||
| ) | [static] |
Definition at line 7705 of file sig_pri.c.
References sig_pri_cc_monitor_instance::core_id.
Referenced by sig_pri_load().
{
const struct sig_pri_cc_monitor_instance *monitor_instance = obj;
return monitor_instance->core_id;
}
| static struct sig_pri_cc_monitor_instance* sig_pri_cc_monitor_instance_init | ( | int | core_id, |
| struct sig_pri_span * | pri, | ||
| long | cc_id, | ||
| const char * | device_name | ||
| ) | [static, read] |
Definition at line 2290 of file sig_pri.c.
References ao2_alloc, ao2_link, sig_pri_span::calls, sig_pri_cc_monitor_instance::cc_id, sig_pri_cc_monitor_instance::core_id, sig_pri_callback::module_ref, sig_pri_callback::module_unref, sig_pri_cc_monitor_instance::name, sig_pri_cc_monitor_instance::pri, and sig_pri_cc_monitor_instance_destroy().
Referenced by sig_pri_cc_available().
{
struct sig_pri_cc_monitor_instance *monitor_instance;
if (!pri->calls->module_ref || !pri->calls->module_unref) {
return NULL;
}
monitor_instance = ao2_alloc(sizeof(*monitor_instance) + strlen(device_name),
sig_pri_cc_monitor_instance_destroy);
if (!monitor_instance) {
return NULL;
}
monitor_instance->cc_id = cc_id;
monitor_instance->pri = pri;
monitor_instance->core_id = core_id;
strcpy(monitor_instance->name, device_name);
pri->calls->module_ref();
ao2_link(sig_pri_cc_monitors, monitor_instance);
return monitor_instance;
}
| int sig_pri_cc_monitor_req_cc | ( | struct ast_cc_monitor * | monitor, |
| int * | available_timer_id | ||
| ) |
Request CCSS.
| monitor | CC core monitor control. |
| available_timer_id | Where to put the available timer scheduler id. Will never be NULL for a device monitor. |
Perform whatever steps are necessary in order to request CC. In addition, the monitor implementation is responsible for starting the available timer in this callback. The scheduler ID for the callback must be stored in the parent_link's child_avail_id field.
| 0 | on success |
| -1 | on failure. |
Definition at line 7753 of file sig_pri.c.
References AST_CC_CCBS, AST_CC_CCNR, ast_mutex_lock, ast_mutex_unlock, sig_pri_cc_monitor_instance::cc_id, sig_pri_span::lock, sig_pri_span::pri, sig_pri_cc_monitor_instance::pri, ast_cc_monitor::private_data, and ast_cc_monitor::service_offered.
{
struct sig_pri_cc_monitor_instance *instance;
int cc_mode;
int res;
switch (monitor->service_offered) {
case AST_CC_CCBS:
cc_mode = 0;/* CCBS */
break;
case AST_CC_CCNR:
cc_mode = 1;/* CCNR */
break;
default:
/* CC service not supported by ISDN. */
return -1;
}
instance = monitor->private_data;
/* libpri handles it's own available timer. */
ast_mutex_lock(&instance->pri->lock);
res = pri_cc_req(instance->pri->pri, instance->cc_id, cc_mode);
ast_mutex_unlock(&instance->pri->lock);
return res;
}
| int sig_pri_cc_monitor_status_rsp | ( | struct ast_cc_monitor * | monitor, |
| enum ast_device_state | devstate | ||
| ) |
Status response to an ast_cc_monitor_status_request().
| monitor | CC core monitor control. |
| devstate | Current status of a Party A device. |
Alert a monitor as to the status of the agent for which the monitor had previously requested a status request.
| 0 | on success |
| -1 | on failure. |
Definition at line 7852 of file sig_pri.c.
References AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, ast_mutex_lock, ast_mutex_unlock, sig_pri_cc_monitor_instance::cc_id, sig_pri_span::lock, sig_pri_span::pri, sig_pri_cc_monitor_instance::pri, and ast_cc_monitor::private_data.
{
struct sig_pri_cc_monitor_instance *instance;
int cc_status;
switch (devstate) {
case AST_DEVICE_UNKNOWN:
case AST_DEVICE_NOT_INUSE:
cc_status = 0;/* free */
break;
case AST_DEVICE_BUSY:
case AST_DEVICE_INUSE:
cc_status = 1;/* busy */
break;
default:
/* Don't know how to interpret this device state into free/busy status. */
return 0;
}
instance = monitor->private_data;
ast_mutex_lock(&instance->pri->lock);
pri_cc_status_req_rsp(instance->pri->pri, instance->cc_id, cc_status);
ast_mutex_unlock(&instance->pri->lock);
return 0;
}
| int sig_pri_cc_monitor_suspend | ( | struct ast_cc_monitor * | monitor | ) |
Suspend monitoring.
| monitor | CC core monitor control. |
Implementers must perform the necessary steps to suspend monitoring.
| 0 | on success |
| -1 | on failure. |
Definition at line 7796 of file sig_pri.c.
References ast_mutex_lock, ast_mutex_unlock, sig_pri_cc_monitor_instance::cc_id, sig_pri_span::lock, sig_pri_span::pri, sig_pri_cc_monitor_instance::pri, and ast_cc_monitor::private_data.
{
struct sig_pri_cc_monitor_instance *instance;
instance = monitor->private_data;
ast_mutex_lock(&instance->pri->lock);
pri_cc_status(instance->pri->pri, instance->cc_id, 1/* busy */);
ast_mutex_unlock(&instance->pri->lock);
return 0;
}
| int sig_pri_cc_monitor_unsuspend | ( | struct ast_cc_monitor * | monitor | ) |
Unsuspend monitoring.
| monitor | CC core monitor control. |
Perform the necessary steps to unsuspend monitoring.
| 0 | on success |
| -1 | on failure. |
Definition at line 7822 of file sig_pri.c.
References ast_mutex_lock, ast_mutex_unlock, sig_pri_cc_monitor_instance::cc_id, sig_pri_span::lock, sig_pri_span::pri, sig_pri_cc_monitor_instance::pri, and ast_cc_monitor::private_data.
{
struct sig_pri_cc_monitor_instance *instance;
instance = monitor->private_data;
ast_mutex_lock(&instance->pri->lock);
pri_cc_status(instance->pri->pri, instance->cc_id, 0/* free */);
ast_mutex_unlock(&instance->pri->lock);
return 0;
}
| void sig_pri_chan_alarm_notify | ( | struct sig_pri_chan * | p, |
| int | noalarm | ||
| ) |
Definition at line 7193 of file sig_pri.c.
References ast_channel::_softhangup, ast_log(), AST_SOFTHANGUP_DEV, sig_pri_chan::call, LOG_WARNING, sig_pri_chan::owner, sig_pri_span::pri, sig_pri_chan::pri, pri_grab(), pri_rel(), and sig_pri_set_alarm().
Referenced by dahdi_handle_event(), handle_init_event(), and mkintf().
{
sig_pri_set_alarm(p, !noalarm);
if (!noalarm) {
if (!p->pri || !p->pri->pri || (pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0)) {
/* T309 is not enabled : hangup calls when alarm occurs */
if (p->call) {
if (p->pri && p->pri->pri) {
if (!pri_grab(p, p->pri)) {
pri_hangup(p->pri->pri, p->call, -1);
pri_destroycall(p->pri->pri, p->call);
p->call = NULL;
pri_rel(p->pri);
} else
ast_log(LOG_WARNING, "Failed to grab PRI!\n");
} else
ast_log(LOG_WARNING, "The PRI Call has not been destroyed\n");
}
if (p->owner)
p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
}
}
}
| void sig_pri_chan_delete | ( | struct sig_pri_chan * | doomed | ) |
Delete the sig_pri private channel structure.
| doomed | sig_pri private channel structure to delete. |
Definition at line 7245 of file sig_pri.c.
References ast_free.
Referenced by destroy_dahdi_pvt().
{
ast_free(doomed);
}
| struct sig_pri_chan* sig_pri_chan_new | ( | void * | pvt_data, |
| struct sig_pri_callback * | callback, | ||
| struct sig_pri_span * | pri, | ||
| int | logicalspan, | ||
| int | channo, | ||
| int | trunkgroup | ||
| ) | [read] |
Definition at line 7217 of file sig_pri.c.
References ast_calloc, sig_pri_chan::calls, sig_pri_chan::chan_pvt, sig_pri_chan::logicalspan, sig_pri_chan::mastertrunkgroup, sig_pri_chan::pri, and sig_pri_chan::prioffset.
Referenced by dahdi_new_pri_nobch_channel(), and mkintf().
{
struct sig_pri_chan *p;
p = ast_calloc(1, sizeof(*p));
if (!p)
return p;
p->logicalspan = logicalspan;
p->prioffset = channo;
p->mastertrunkgroup = trunkgroup;
p->calls = callback;
p->chan_pvt = pvt_data;
p->pri = pri;
return p;
}
| void sig_pri_cli_show_span | ( | int | fd, |
| int * | dchannels, | ||
| struct sig_pri_span * | pri | ||
| ) |
Definition at line 7281 of file sig_pri.c.
References ast_cli(), build_status(), DAHDI_OVERLAPDIAL_INCOMING, sig_pri_span::dchanavail, sig_pri_span::dchans, free, sig_pri_span::overlapdial, sig_pri_span::pri, pri_order(), SIG_PRI_NUM_DCHANS, and status.
Referenced by handle_pri_show_span().
{
int x;
char status[256];
for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
if (pri->dchans[x]) {
#ifdef PRI_DUMP_INFO_STR
char *info_str = NULL;
#endif
ast_cli(fd, "%s D-channel: %d\n", pri_order(x), dchannels[x]);
build_status(status, sizeof(status), pri->dchanavail[x], pri->dchans[x] == pri->pri);
ast_cli(fd, "Status: %s\n", status);
#ifdef PRI_DUMP_INFO_STR
info_str = pri_dump_info_str(pri->pri);
if (info_str) {
ast_cli(fd, "%s", info_str);
free(info_str);
}
#else
pri_dump_info(pri->pri);
#endif
ast_cli(fd, "Overlap Recv: %s\n\n", (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)?"Yes":"No");
ast_cli(fd, "\n");
}
}
}
| void sig_pri_cli_show_spans | ( | int | fd, |
| int | span, | ||
| struct sig_pri_span * | pri | ||
| ) |
Definition at line 7269 of file sig_pri.c.
References ast_cli(), build_status(), sig_pri_span::dchanavail, sig_pri_span::dchans, sig_pri_span::pri, SIG_PRI_NUM_DCHANS, and status.
Referenced by handle_pri_show_spans().
{
char status[256];
int x;
for (x = 0; x < SIG_PRI_NUM_DCHANS; x++) {
if (pri->dchans[x]) {
build_status(status, sizeof(status), pri->dchanavail[x], pri->dchans[x] == pri->pri);
ast_cli(fd, "PRI span %d/%d: %s\n", span, x, status);
}
}
}
| static int sig_pri_cmp_pri_chans | ( | const void * | left, |
| const void * | right | ||
| ) | [static] |
Definition at line 6977 of file sig_pri.c.
References sig_pri_chan::channel.
Referenced by sig_pri_sort_pri_chans().
{
const struct sig_pri_chan *pvt_left;
const struct sig_pri_chan *pvt_right;
pvt_left = *(struct sig_pri_chan **) left;
pvt_right = *(struct sig_pri_chan **) right;
if (!pvt_left) {
if (!pvt_right) {
return 0;
}
return 1;
}
if (!pvt_right) {
return -1;
}
return pvt_left->channel - pvt_right->channel;
}
| static struct sig_pri_chan* sig_pri_cw_available | ( | struct sig_pri_span * | pri | ) | [static, read] |
Definition at line 6743 of file sig_pri.c.
References ast_atomic_fetchadd_int(), ast_mutex_lock, ast_mutex_unlock, sig_pri_chan::is_call_waiting, sig_pri_span::lock, sig_pri_span::max_call_waiting_calls, sig_pri_span::num_call_waiting_calls, sig_pri_span::numchans, pri_find_empty_nobch(), sig_pri_span::pvts, sig_pri_available_check(), and sig_pri_init_config().
Referenced by sig_pri_available().
{
struct sig_pri_chan *cw;
int idx;
cw = NULL;
ast_mutex_lock(&pri->lock);
if (pri->num_call_waiting_calls < pri->max_call_waiting_calls) {
if (!pri->num_call_waiting_calls) {
/*
* There are no outstanding call waiting calls. Check to see
* if the span is in a congested state for the first call
* waiting call.
*/
for (idx = 0; idx < pri->numchans; ++idx) {
if (pri->pvts[idx] && sig_pri_available_check(pri->pvts[idx])) {
/* There is another channel that is available on this span. */
ast_mutex_unlock(&pri->lock);
return cw;
}
}
}
idx = pri_find_empty_nobch(pri);
if (0 <= idx) {
/* Setup the call waiting interface to use. */
cw = pri->pvts[idx];
cw->is_call_waiting = 1;
sig_pri_init_config(cw, pri);
ast_atomic_fetchadd_int(&pri->num_call_waiting_calls, 1);
}
}
ast_mutex_unlock(&pri->lock);
return cw;
}
| int sig_pri_digit_begin | ( | struct sig_pri_chan * | pvt, |
| struct ast_channel * | ast, | ||
| char | digit | ||
| ) |
Definition at line 6819 of file sig_pri.c.
References ast_channel::_state, ast_debug, ast_log(), AST_STATE_DIALING, sig_pri_chan::call, sig_pri_chan::dialdest, LOG_WARNING, sig_pri_span::pri, sig_pri_chan::pri, pri_grab(), pri_rel(), sig_pri_chan::proceeding, sig_pri_chan::setup_ack, and sig_pri_span::span.
Referenced by dahdi_digit_begin().
{
if ((ast->_state == AST_STATE_DIALING) && !pvt->proceeding) {
if (pvt->setup_ack) {
if (!pri_grab(pvt, pvt->pri)) {
pri_information(pvt->pri->pri, pvt->call, digit);
pri_rel(pvt->pri);
} else {
ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", pvt->pri->span);
}
} else if (strlen(pvt->dialdest) < sizeof(pvt->dialdest) - 1) {
int res;
ast_debug(1, "Queueing digit '%c' since setup_ack not yet received\n", digit);
res = strlen(pvt->dialdest);
pvt->dialdest[res++] = digit;
pvt->dialdest[res] = '\0';
}
return 0;
}
return 1;
}
| static void sig_pri_dsp_reset_and_flush_digits | ( | struct sig_pri_chan * | p | ) | [static] |
Definition at line 835 of file sig_pri.c.
References sig_pri_chan::calls, sig_pri_chan::chan_pvt, and sig_pri_callback::dsp_reset_and_flush_digits.
Referenced by pri_ss_thread().
{
if (p->calls->dsp_reset_and_flush_digits) {
p->calls->dsp_reset_and_flush_digits(p->chan_pvt);
}
}
| static void sig_pri_event_party_id | ( | struct ast_str ** | msg, |
| const char * | prefix, | ||
| struct ast_party_id * | party | ||
| ) | [static] |
Definition at line 1833 of file sig_pri.c.
References ast_describe_caller_presentation(), ast_party_id_presentation(), ast_party_name_charset_describe(), ast_str_append(), ast_party_name::char_set, ast_party_id::name, ast_party_id::number, ast_party_subaddress::odd_even_indicator, ast_party_number::plan, ast_party_name::presentation, ast_party_number::presentation, S_COR, S_OR, ast_party_subaddress::str, ast_party_name::str, ast_party_number::str, ast_party_id::subaddress, ast_party_subaddress::type, ast_party_subaddress::valid, ast_party_name::valid, and ast_party_number::valid.
Referenced by sig_pri_mcid_event().
{
int pres;
/* Combined party presentation */
pres = ast_party_id_presentation(party);
ast_str_append(msg, 0, "%sPres: %d (%s)\r\n", prefix, pres,
ast_describe_caller_presentation(pres));
/* Party number */
ast_str_append(msg, 0, "%sNumValid: %d\r\n", prefix,
(unsigned) party->number.valid);
ast_str_append(msg, 0, "%sNum: %s\r\n", prefix,
S_COR(party->number.valid, party->number.str, ""));
ast_str_append(msg, 0, "%ston: %d\r\n", prefix, party->number.plan);
if (party->number.valid) {
ast_str_append(msg, 0, "%sNumPlan: %d\r\n", prefix, party->number.plan);
ast_str_append(msg, 0, "%sNumPres: %d (%s)\r\n", prefix,
party->number.presentation,
ast_describe_caller_presentation(party->number.presentation));
}
/* Party name */
ast_str_append(msg, 0, "%sNameValid: %d\r\n", prefix,
(unsigned) party->name.valid);
ast_str_append(msg, 0, "%sName: %s\r\n", prefix,
S_COR(party->name.valid, party->name.str, ""));
if (party->name.valid) {
ast_str_append(msg, 0, "%sNameCharSet: %s\r\n", prefix,
ast_party_name_charset_describe(party->name.char_set));
ast_str_append(msg, 0, "%sNamePres: %d (%s)\r\n", prefix,
party->name.presentation,
ast_describe_caller_presentation(party->name.presentation));
}
#if defined(HAVE_PRI_SUBADDR)
/* Party subaddress */
if (party->subaddress.valid) {
static const char subaddress[] = "Subaddr";
ast_str_append(msg, 0, "%s%s: %s\r\n", prefix, subaddress,
S_OR(party->subaddress.str, ""));
ast_str_append(msg, 0, "%s%sType: %d\r\n", prefix, subaddress,
party->subaddress.type);
ast_str_append(msg, 0, "%s%sOdd: %d\r\n", prefix, subaddress,
party->subaddress.odd_even_indicator);
}
#endif /* defined(HAVE_PRI_SUBADDR) */
}
| void sig_pri_extract_called_num_subaddr | ( | struct sig_pri_chan * | p, |
| const char * | rdest, | ||
| char * | called, | ||
| size_t | called_buff_size | ||
| ) |
Extract the called number and subaddress from the dial string.
| p | sig_pri channel structure. |
| rdest | Dial string buffer to extract called number and subaddress. |
| called | Buffer to fill with extracted <number>[:<subaddress>] |
| called_buff_size | Size of buffer to fill. |
Definition at line 5957 of file sig_pri.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ext, and sig_pri_chan::stripmsd.
Referenced by dahdi_request().
{
char *dial;
char *number;
char *subaddr;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(group); /* channel/group token */
AST_APP_ARG(ext); /* extension token */
//AST_APP_ARG(opts); /* options token */
AST_APP_ARG(other); /* Any remining unused arguments */
);
/* Get private copy of dial string and break it up. */
dial = ast_strdupa(rdest);
AST_NONSTANDARD_APP_ARGS(args, dial, '/');
number = args.ext;
if (!number) {
number = "";
}
/* Find and extract dialed_subaddress */
subaddr = strchr(number, ':');
if (subaddr) {
*subaddr++ = '\0';
/* Skip subaddress type prefix. */
switch (*subaddr) {
case 'U':
case 'u':
case 'N':
case 'n':
++subaddr;
break;
default:
break;
}
}
/* Skip type-of-number/dial-plan prefix characters. */
if (strlen(number) < p->stripmsd) {
number = "";
} else {
number += p->stripmsd;
while (isalpha(*number)) {
++number;
}
}
/* Fill buffer with extracted number and subaddress. */
if (ast_strlen_zero(subaddr)) {
/* Put in called number only since there is no subaddress. */
snprintf(called, called_buff_size, "%s", number);
} else {
/* Put in called number and subaddress. */
snprintf(called, called_buff_size, "%s:%s", number, subaddr);
}
}
| static struct ast_cc_agent* sig_pri_find_cc_agent_by_cc_id | ( | struct sig_pri_span * | pri, |
| long | cc_id | ||
| ) | [static, read] |
Definition at line 2186 of file sig_pri.c.
References ast_cc_agent_callback(), sig_pri_cc_agent_prv::cc_id, sig_pri_cc_agent_prv::pri, sig_pri_cc_agent_cmp_cc_id(), and sig_pri_cc_type_name.
Referenced by sig_pri_cc_link_canceled(), sig_pri_handle_cis_subcmds(), and sig_pri_handle_subcmds().
{
struct sig_pri_cc_agent_prv finder = {
.pri = pri,
.cc_id = cc_id,
};
return ast_cc_agent_callback(0, sig_pri_cc_agent_cmp_cc_id, &finder,
sig_pri_cc_type_name);
}
| static struct sig_pri_cc_monitor_instance* sig_pri_find_cc_monitor_by_cc_id | ( | struct sig_pri_span * | pri, |
| long | cc_id | ||
| ) | [static, read] |
Definition at line 2237 of file sig_pri.c.
References ao2_callback, sig_pri_cc_monitor_instance::cc_id, sig_pri_cc_monitor_instance::pri, and sig_pri_cc_monitor_cmp_cc_id().
Referenced by sig_pri_cc_link_canceled(), and sig_pri_handle_cis_subcmds().
{
struct sig_pri_cc_monitor_instance finder = {
.pri = pri,
.cc_id = cc_id,
};
return ao2_callback(sig_pri_cc_monitors, 0, sig_pri_cc_monitor_cmp_cc_id, &finder);
}
| void sig_pri_fixup | ( | struct ast_channel * | oldchan, |
| struct ast_channel * | newchan, | ||
| struct sig_pri_chan * | pchan | ||
| ) |
Definition at line 7367 of file sig_pri.c.
References sig_pri_chan::owner.
Referenced by dahdi_fixup().
| static void sig_pri_fixup_chans | ( | struct sig_pri_chan * | old_chan, |
| struct sig_pri_chan * | new_chan | ||
| ) | [static] |
Definition at line 850 of file sig_pri.c.
References sig_pri_chan::calls, sig_pri_chan::chan_pvt, and sig_pri_callback::fixup_chans.
Referenced by pri_fixup_principle().
{
if (old_chan->calls->fixup_chans)
old_chan->calls->fixup_chans(old_chan->chan_pvt, new_chan->chan_pvt);
}
| static const char* sig_pri_get_orig_dialstring | ( | struct sig_pri_chan * | p | ) | [static] |
Definition at line 155 of file sig_pri.c.
References ast_log(), sig_pri_chan::calls, sig_pri_chan::chan_pvt, sig_pri_callback::get_orig_dialstring, and LOG_ERROR.
Referenced by sig_pri_cc_available(), and sig_pri_cc_generic_check().
{
if (p->calls->get_orig_dialstring) {
return p->calls->get_orig_dialstring(p->chan_pvt);
}
ast_log(LOG_ERROR, "get_orig_dialstring callback not defined\n");
return "";
}
| static void sig_pri_handle_cis_subcmds | ( | struct sig_pri_span * | pri, |
| int | event_id, | ||
| const struct pri_subcommands * | subcmds, | ||
| q931_call * | call_rsp | ||
| ) | [static] |
Definition at line 3506 of file sig_pri.c.
References ao2_ref, ast_cc_agent_accept_request(), ast_cc_agent_caller_available(), ast_cc_agent_caller_busy(), ast_cc_agent_status_response(), ast_cc_failed(), ast_cc_monitor_callee_available(), ast_cc_monitor_failed(), ast_cc_monitor_party_b_free(), ast_cc_monitor_request_acked(), ast_cc_monitor_status_request(), ast_cc_monitor_stop_ringing(), ast_cc_request_is_within_limits(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, ast_verb, sig_pri_cc_agent_prv::cc_request_response_pending, sig_pri_cc_monitor_instance::core_id, ast_cc_agent::core_id, monitor, sig_pri_cc_monitor_instance::name, sig_pri_span::pri, ast_cc_agent::private_data, sig_pri_aoc_e_from_pri(), sig_pri_cc_link_canceled(), sig_pri_cc_type_name, sig_pri_find_cc_agent_by_cc_id(), sig_pri_find_cc_monitor_by_cc_id(), and sig_pri_span::span.
Referenced by pri_dchannel().
{
int index;
#if defined(HAVE_PRI_CCSS)
struct ast_cc_agent *agent;
struct sig_pri_cc_agent_prv *agent_prv;
struct sig_pri_cc_monitor_instance *monitor;
#endif /* defined(HAVE_PRI_CCSS) */
if (!subcmds) {
return;
}
for (index = 0; index < subcmds->counter_subcmd; ++index) {
const struct pri_subcommand *subcmd = &subcmds->subcmd[index];
switch (subcmd->cmd) {
#if defined(STATUS_REQUEST_PLACE_HOLDER)
case PRI_SUBCMD_STATUS_REQ:
case PRI_SUBCMD_STATUS_REQ_RSP:
/* Ignore for now. */
break;
#endif /* defined(STATUS_REQUEST_PLACE_HOLDER) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_REQ:
agent = sig_pri_find_cc_agent_by_cc_id(pri, subcmd->u.cc_request.cc_id);
if (!agent) {
pri_cc_cancel(pri->pri, subcmd->u.cc_request.cc_id);
break;
}
if (!ast_cc_request_is_within_limits()) {
if (pri_cc_req_rsp(pri->pri, subcmd->u.cc_request.cc_id,
5/* queue_full */)) {
pri_cc_cancel(pri->pri, subcmd->u.cc_request.cc_id);
}
ast_cc_failed(agent->core_id, "%s agent system CC queue full",
sig_pri_cc_type_name);
ao2_ref(agent, -1);
break;
}
agent_prv = agent->private_data;
agent_prv->cc_request_response_pending = 1;
if (ast_cc_agent_accept_request(agent->core_id,
"%s caller accepted CC offer.", sig_pri_cc_type_name)) {
agent_prv->cc_request_response_pending = 0;
if (pri_cc_req_rsp(pri->pri, subcmd->u.cc_request.cc_id,
2/* short_term_denial */)) {
pri_cc_cancel(pri->pri, subcmd->u.cc_request.cc_id);
}
ast_cc_failed(agent->core_id, "%s agent CC core request accept failed",
sig_pri_cc_type_name);
}
ao2_ref(agent, -1);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_REQ_RSP:
monitor = sig_pri_find_cc_monitor_by_cc_id(pri,
subcmd->u.cc_request_rsp.cc_id);
if (!monitor) {
pri_cc_cancel(pri->pri, subcmd->u.cc_request_rsp.cc_id);
break;
}
switch (subcmd->u.cc_request_rsp.status) {
case 0:/* success */
ast_cc_monitor_request_acked(monitor->core_id,
"%s far end accepted CC request", sig_pri_cc_type_name);
break;
case 1:/* timeout */
ast_verb(2, "core_id:%d %s CC request timeout\n", monitor->core_id,
sig_pri_cc_type_name);
ast_cc_monitor_failed(monitor->core_id, monitor->name,
"%s CC request timeout", sig_pri_cc_type_name);
break;
case 2:/* error */
ast_verb(2, "core_id:%d %s CC request error: %s\n", monitor->core_id,
sig_pri_cc_type_name,
pri_facility_error2str(subcmd->u.cc_request_rsp.fail_code));
ast_cc_monitor_failed(monitor->core_id, monitor->name,
"%s CC request error", sig_pri_cc_type_name);
break;
case 3:/* reject */
ast_verb(2, "core_id:%d %s CC request reject: %s\n", monitor->core_id,
sig_pri_cc_type_name,
pri_facility_reject2str(subcmd->u.cc_request_rsp.fail_code));
ast_cc_monitor_failed(monitor->core_id, monitor->name,
"%s CC request reject", sig_pri_cc_type_name);
break;
default:
ast_verb(2, "core_id:%d %s CC request unknown status %d\n",
monitor->core_id, sig_pri_cc_type_name,
subcmd->u.cc_request_rsp.status);
ast_cc_monitor_failed(monitor->core_id, monitor->name,
"%s CC request unknown status", sig_pri_cc_type_name);
break;
}
ao2_ref(monitor, -1);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_REMOTE_USER_FREE:
monitor = sig_pri_find_cc_monitor_by_cc_id(pri,
subcmd->u.cc_remote_user_free.cc_id);
if (!monitor) {
pri_cc_cancel(pri->pri, subcmd->u.cc_remote_user_free.cc_id);
break;
}
ast_cc_monitor_callee_available(monitor->core_id,
"%s callee has become available", sig_pri_cc_type_name);
ao2_ref(monitor, -1);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_B_FREE:
monitor = sig_pri_find_cc_monitor_by_cc_id(pri,
subcmd->u.cc_b_free.cc_id);
if (!monitor) {
pri_cc_cancel(pri->pri, subcmd->u.cc_b_free.cc_id);
break;
}
ast_cc_monitor_party_b_free(monitor->core_id);
ao2_ref(monitor, -1);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_STATUS_REQ:
monitor = sig_pri_find_cc_monitor_by_cc_id(pri,
subcmd->u.cc_status_req.cc_id);
if (!monitor) {
pri_cc_cancel(pri->pri, subcmd->u.cc_status_req.cc_id);
break;
}
ast_cc_monitor_status_request(monitor->core_id);
ao2_ref(monitor, -1);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_STATUS_REQ_RSP:
agent = sig_pri_find_cc_agent_by_cc_id(pri, subcmd->u.cc_status_req_rsp.cc_id);
if (!agent) {
pri_cc_cancel(pri->pri, subcmd->u.cc_status_req_rsp.cc_id);
break;
}
ast_cc_agent_status_response(agent->core_id,
subcmd->u.cc_status_req_rsp.status ? AST_DEVICE_INUSE
: AST_DEVICE_NOT_INUSE);
ao2_ref(agent, -1);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_STATUS:
agent = sig_pri_find_cc_agent_by_cc_id(pri, subcmd->u.cc_status.cc_id);
if (!agent) {
pri_cc_cancel(pri->pri, subcmd->u.cc_status.cc_id);
break;
}
if (subcmd->u.cc_status.status) {
ast_cc_agent_caller_busy(agent->core_id, "%s agent caller is busy",
sig_pri_cc_type_name);
} else {
ast_cc_agent_caller_available(agent->core_id,
"%s agent caller is available", sig_pri_cc_type_name);
}
ao2_ref(agent, -1);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_CANCEL:
sig_pri_cc_link_canceled(pri, subcmd->u.cc_cancel.cc_id,
subcmd->u.cc_cancel.is_agent);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_STOP_ALERTING:
monitor = sig_pri_find_cc_monitor_by_cc_id(pri,
subcmd->u.cc_stop_alerting.cc_id);
if (!monitor) {
pri_cc_cancel(pri->pri, subcmd->u.cc_stop_alerting.cc_id);
break;
}
ast_cc_monitor_stop_ringing(monitor->core_id);
ao2_ref(monitor, -1);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_AOC_EVENTS)
case PRI_SUBCMD_AOC_E:
/* Queue AST_CONTROL_AOC frame */
sig_pri_aoc_e_from_pri(&subcmd->u.aoc_e, NULL, 0);
break;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
default:
ast_debug(2,
"Unknown CIS subcommand(%d) in %s event on span %d.\n",
subcmd->cmd, pri_event2str(event_id), pri->span);
break;
}
}
}
| static void sig_pri_handle_dchan_exception | ( | struct sig_pri_span * | pri, |
| int | index | ||
| ) | [static] |
Definition at line 126 of file sig_pri.c.
References sig_pri_span::calls, and sig_pri_callback::handle_dchan_exception.
Referenced by pri_dchannel().
{
if (pri->calls->handle_dchan_exception)
pri->calls->handle_dchan_exception(pri, index);
}
| static int sig_pri_handle_hold | ( | struct sig_pri_span * | pri, |
| pri_event * | ev | ||
| ) | [static] |
Definition at line 4103 of file sig_pri.c.
References ast_bridged_channel(), ast_channel_unlock, AST_CONTROL_HOLD, AST_FRAME_CONTROL, ast_log(), ast_queue_frame(), ast_frame_subclass::integer, LOG_WARNING, sig_pri_chan::no_b_channel, sig_pri_chan::owner, PRI_CHANNEL, pri_find_empty_nobch(), pri_find_principle(), pri_fixup_principle(), PRI_SPAN, sig_pri_span::pvts, sig_pri_handle_subcmds(), sig_pri_lock_owner(), sig_pri_lock_private(), sig_pri_span_devstate_changed(), sig_pri_unlock_private(), sig_pri_span::span, and ast_frame::subclass.
Referenced by pri_dchannel().
{
int retval;
int chanpos_old;
int chanpos_new;
struct ast_channel *bridged;
struct ast_channel *owner;
chanpos_old = pri_find_principle(pri, ev->hold.channel, ev->hold.call);
if (chanpos_old < 0) {
ast_log(LOG_WARNING,
"Received HOLD on unconfigured channel %d/%d span %d\n",
PRI_SPAN(ev->hold.channel), PRI_CHANNEL(ev->hold.channel), pri->span);
return -1;
}
if (pri->pvts[chanpos_old]->no_b_channel) {
/* Call is already on hold or is call waiting call. */
return -1;
}
sig_pri_lock_private(pri->pvts[chanpos_old]);
sig_pri_lock_owner(pri, chanpos_old);
owner = pri->pvts[chanpos_old]->owner;
if (!owner) {
retval = -1;
goto done_with_private;
}
bridged = ast_bridged_channel(owner);
if (!bridged) {
/* Cannot hold a call that is not bridged. */
retval = -1;
goto done_with_owner;
}
chanpos_new = pri_find_empty_nobch(pri);
if (chanpos_new < 0) {
/* No hold channel available. */
retval = -1;
goto done_with_owner;
}
sig_pri_handle_subcmds(pri, chanpos_old, ev->e, ev->hold.channel, ev->hold.subcmds,
ev->hold.call);
chanpos_new = pri_fixup_principle(pri, chanpos_new, ev->hold.call);
if (chanpos_new < 0) {
/* Should never happen. */
retval = -1;
} else {
struct ast_frame f = { AST_FRAME_CONTROL, };
/*
* Things are in an odd state here so we cannot use pri_queue_control().
* However, we already have the owner lock so we can simply queue the frame.
*/
f.subclass.integer = AST_CONTROL_HOLD;
ast_queue_frame(owner, &f);
sig_pri_span_devstate_changed(pri);
retval = 0;
}
done_with_owner:;
ast_channel_unlock(owner);
done_with_private:;
sig_pri_unlock_private(pri->pvts[chanpos_old]);
return retval;
}
| static void sig_pri_handle_retrieve | ( | struct sig_pri_span * | pri, |
| pri_event * | ev | ||
| ) | [static] |
Definition at line 4184 of file sig_pri.c.
References AST_CONTROL_UNHOLD, sig_pri_span::pri, PRI_CHANNEL, pri_find_empty_chan(), pri_find_principle(), pri_fixup_principle(), PRI_HELD_CALL, pri_queue_control(), PVT_TO_CHANNEL(), sig_pri_span::pvts, pvts, sig_pri_handle_subcmds(), sig_pri_lock_private(), sig_pri_span_devstate_changed(), and sig_pri_unlock_private().
Referenced by pri_dchannel().
{
int chanpos;
if (!(ev->retrieve.channel & PRI_HELD_CALL)
|| pri_find_principle(pri, ev->retrieve.channel, ev->retrieve.call) < 0) {
/* The call is not currently held. */
pri_retrieve_rej(pri->pri, ev->retrieve.call,
PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED);
return;
}
if (PRI_CHANNEL(ev->retrieve.channel) == 0xFF) {
chanpos = pri_find_empty_chan(pri, 1);
} else {
chanpos = pri_find_principle(pri,
ev->retrieve.channel & ~PRI_HELD_CALL, ev->retrieve.call);
if (ev->retrieve.flexible
&& (chanpos < 0 || pri->pvts[chanpos]->owner)) {
/*
* Channel selection is flexible and the requested channel
* is bad or already in use. Pick another channel.
*/
chanpos = pri_find_empty_chan(pri, 1);
}
}
if (chanpos < 0) {
pri_retrieve_rej(pri->pri, ev->retrieve.call,
ev->retrieve.flexible ? PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION
: PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
return;
}
chanpos = pri_fixup_principle(pri, chanpos, ev->retrieve.call);
if (chanpos < 0) {
/* Channel is already in use. */
pri_retrieve_rej(pri->pri, ev->retrieve.call,
PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
return;
}
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->retrieve.channel,
ev->retrieve.subcmds, ev->retrieve.call);
pri_queue_control(pri, chanpos, AST_CONTROL_UNHOLD);
sig_pri_unlock_private(pri->pvts[chanpos]);
sig_pri_span_devstate_changed(pri);
pri_retrieve_ack(pri->pri, ev->retrieve.call,
PVT_TO_CHANNEL(pri->pvts[chanpos]));
}
| static void sig_pri_handle_subcmds | ( | struct sig_pri_span * | pri, |
| int | chanpos, | ||
| int | event_id, | ||
| int | channel, | ||
| const struct pri_subcommands * | subcmds, | ||
| q931_call * | call_rsp | ||
| ) | [static] |
Definition at line 3762 of file sig_pri.c.
References ast_party_caller::ani, ao2_ref, sig_pri_span::aoc_passthrough_flag, ast_cc_agent_recalling(), ast_cc_agent_set_interfaces_chanvar(), AST_CC_CCBS, AST_CC_CCNR, AST_CC_NONE, ast_channel_queue_connected_line_update(), ast_channel_queue_redirecting_update(), ast_channel_set_caller_event(), ast_channel_set_redirecting(), ast_channel_unlock, AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_BUSY, ast_copy_string(), ast_debug, ast_log(), ast_party_caller_set_init(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_party_id_presentation(), ast_party_redirecting_free(), ast_party_subaddress_set(), ast_queue_control(), ast_setup_cc_recall_datastore(), ast_strdup, ast_string_field_set, xfer_rsp_data::call, ast_channel::caller, sig_pri_chan::callingpres, sig_pri_chan::cid_name, sig_pri_chan::cid_num, sig_pri_chan::cid_subaddr, sig_pri_chan::cid_ton, ast_cc_agent::core_id, ast_party_redirecting::from, ast_party_caller::id, ast_party_connected_line::id, xfer_rsp_data::invoke_id, LOG_ERROR, LOG_WARNING, ast_party_id::name, ast_party_id::number, sig_pri_chan::owner, ast_party_number::plan, xfer_rsp_data::pri, sig_pri_span::pri, PRI_CHANNEL, PRI_SPAN, sig_pri_span::pvts, ast_channel::redirecting, service, sig_pri_aoc_d_from_pri(), sig_pri_aoc_e_from_pri(), SIG_PRI_AOC_GRANT_D, SIG_PRI_AOC_GRANT_E, SIG_PRI_AOC_GRANT_S, sig_pri_aoc_request_from_pri(), sig_pri_aoc_s_from_pri(), sig_pri_attempt_transfer(), sig_pri_cc_available(), sig_pri_cc_link_canceled(), sig_pri_cc_type_name, sig_pri_find_cc_agent_by_cc_id(), sig_pri_lock_owner(), sig_pri_lock_private(), sig_pri_mcid_event(), sig_pri_party_id_convert(), sig_pri_redirecting_convert(), sig_pri_set_caller_id(), sig_pri_transfer_rsp(), sig_pri_unlock_private(), ast_party_connected_line::source, sig_pri_span::span, ast_party_subaddress::str, ast_party_number::str, ast_party_name::str, ast_party_id::subaddress, ast_party_id::tag, ast_party_redirecting::to, sig_pri_span::transfer, sig_pri_chan::user_tag, and ast_party_subaddress::valid.
Referenced by pri_dchannel(), sig_pri_handle_hold(), and sig_pri_handle_retrieve().
{
int index;
struct ast_channel *owner;
struct ast_party_redirecting ast_redirecting;
#if defined(HAVE_PRI_TRANSFER)
struct xfer_rsp_data xfer_rsp;
#endif /* defined(HAVE_PRI_TRANSFER) */
if (!subcmds) {
return;
}
for (index = 0; index < subcmds->counter_subcmd; ++index) {
const struct pri_subcommand *subcmd = &subcmds->subcmd[index];
switch (subcmd->cmd) {
case PRI_SUBCMD_CONNECTED_LINE:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
struct ast_party_connected_line ast_connected;
int caller_id_update;
/* Extract the connected line information */
ast_party_connected_line_init(&ast_connected);
sig_pri_party_id_convert(&ast_connected.id, &subcmd->u.connected_line.id,
pri);
ast_connected.id.tag = ast_strdup(pri->pvts[chanpos]->user_tag);
caller_id_update = 0;
if (ast_connected.id.name.str) {
/* Save name for Caller-ID update */
ast_copy_string(pri->pvts[chanpos]->cid_name,
ast_connected.id.name.str, sizeof(pri->pvts[chanpos]->cid_name));
caller_id_update = 1;
}
if (ast_connected.id.number.str) {
/* Save number for Caller-ID update */
ast_copy_string(pri->pvts[chanpos]->cid_num,
ast_connected.id.number.str, sizeof(pri->pvts[chanpos]->cid_num));
pri->pvts[chanpos]->cid_ton = ast_connected.id.number.plan;
caller_id_update = 1;
}
ast_connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
pri->pvts[chanpos]->cid_subaddr[0] = '\0';
#if defined(HAVE_PRI_SUBADDR)
if (ast_connected.id.subaddress.valid) {
ast_party_subaddress_set(&owner->caller.id.subaddress,
&ast_connected.id.subaddress);
if (ast_connected.id.subaddress.str) {
ast_copy_string(pri->pvts[chanpos]->cid_subaddr,
ast_connected.id.subaddress.str,
sizeof(pri->pvts[chanpos]->cid_subaddr));
}
}
#endif /* defined(HAVE_PRI_SUBADDR) */
if (caller_id_update) {
struct ast_party_caller ast_caller;
pri->pvts[chanpos]->callingpres =
ast_party_id_presentation(&ast_connected.id);
sig_pri_set_caller_id(pri->pvts[chanpos]);
ast_party_caller_set_init(&ast_caller, &owner->caller);
ast_caller.id = ast_connected.id;
ast_caller.ani = ast_connected.id;
ast_channel_set_caller_event(owner, &ast_caller, NULL);
}
/* Update the connected line information on the other channel */
if (event_id != PRI_EVENT_RING) {
/* This connected_line update was not from a SETUP message. */
ast_channel_queue_connected_line_update(owner, &ast_connected, NULL);
}
ast_party_connected_line_free(&ast_connected);
ast_channel_unlock(owner);
}
break;
case PRI_SUBCMD_REDIRECTING:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
sig_pri_redirecting_convert(&ast_redirecting, &subcmd->u.redirecting,
&owner->redirecting, pri);
ast_redirecting.from.tag = ast_strdup(pri->pvts[chanpos]->user_tag);
ast_redirecting.to.tag = ast_strdup(pri->pvts[chanpos]->user_tag);
/*! \todo XXX Original called data can be put in a channel data store that is inherited. */
ast_channel_set_redirecting(owner, &ast_redirecting, NULL);
if (event_id != PRI_EVENT_RING) {
/* This redirection was not from a SETUP message. */
ast_channel_queue_redirecting_update(owner, &ast_redirecting, NULL);
}
ast_party_redirecting_free(&ast_redirecting);
ast_channel_unlock(owner);
}
break;
#if defined(HAVE_PRI_CALL_REROUTING)
case PRI_SUBCMD_REROUTING:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
struct pri_party_redirecting pri_deflection;
if (!call_rsp) {
ast_channel_unlock(owner);
ast_log(LOG_WARNING,
"CallRerouting/CallDeflection to '%s' without call!\n",
subcmd->u.rerouting.deflection.to.number.str);
break;
}
pri_deflection = subcmd->u.rerouting.deflection;
ast_string_field_set(owner, call_forward, pri_deflection.to.number.str);
/* Adjust the deflecting to number based upon the subscription option. */
switch (subcmd->u.rerouting.subscription_option) {
case 0: /* noNotification */
case 1: /* notificationWithoutDivertedToNr */
/* Delete the number because the far end is not supposed to see it. */
pri_deflection.to.number.presentation =
PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
pri_deflection.to.number.plan =
(PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164;
pri_deflection.to.number.str[0] = '\0';
break;
case 2: /* notificationWithDivertedToNr */
break;
case 3: /* notApplicable */
default:
break;
}
sig_pri_redirecting_convert(&ast_redirecting, &pri_deflection,
&owner->redirecting, pri);
ast_redirecting.from.tag = ast_strdup(pri->pvts[chanpos]->user_tag);
ast_redirecting.to.tag = ast_strdup(pri->pvts[chanpos]->user_tag);
ast_channel_set_redirecting(owner, &ast_redirecting, NULL);
ast_party_redirecting_free(&ast_redirecting);
/*
* Send back positive ACK to CallRerouting/CallDeflection.
*
* Note: This call will be hungup by the dial application when
* it processes the call_forward string set above.
*/
pri_rerouting_rsp(pri->pri, call_rsp, subcmd->u.rerouting.invoke_id,
PRI_REROUTING_RSP_OK_CLEAR);
/* This line is BUSY to further attempts by this dialing attempt. */
ast_queue_control(owner, AST_CONTROL_BUSY);
ast_channel_unlock(owner);
}
break;
#endif /* defined(HAVE_PRI_CALL_REROUTING) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_AVAILABLE:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
enum ast_cc_service_type service;
switch (event_id) {
case PRI_EVENT_RINGING:
service = AST_CC_CCNR;
break;
case PRI_EVENT_HANGUP_REQ:
/* We will assume that the cause was busy/congestion. */
service = AST_CC_CCBS;
break;
default:
service = AST_CC_NONE;
break;
}
if (service == AST_CC_NONE
|| sig_pri_cc_available(pri, chanpos, subcmd->u.cc_available.cc_id,
service)) {
pri_cc_cancel(pri->pri, subcmd->u.cc_available.cc_id);
}
ast_channel_unlock(owner);
} else {
/* No asterisk channel. */
pri_cc_cancel(pri->pri, subcmd->u.cc_available.cc_id);
}
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_CALL:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
struct ast_cc_agent *agent;
agent = sig_pri_find_cc_agent_by_cc_id(pri, subcmd->u.cc_call.cc_id);
if (agent) {
ast_setup_cc_recall_datastore(owner, agent->core_id);
ast_cc_agent_set_interfaces_chanvar(owner);
ast_cc_agent_recalling(agent->core_id,
"%s caller is attempting recall", sig_pri_cc_type_name);
ao2_ref(agent, -1);
}
ast_channel_unlock(owner);
}
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_CANCEL:
sig_pri_cc_link_canceled(pri, subcmd->u.cc_cancel.cc_id,
subcmd->u.cc_cancel.is_agent);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_TRANSFER)
case PRI_SUBCMD_TRANSFER_CALL:
if (!call_rsp) {
/* Should never happen. */
ast_log(LOG_ERROR,
"Call transfer subcommand without call to send response!\n");
break;
}
sig_pri_unlock_private(pri->pvts[chanpos]);
xfer_rsp.pri = pri;
xfer_rsp.call = call_rsp;
xfer_rsp.invoke_id = subcmd->u.transfer.invoke_id;
sig_pri_attempt_transfer(pri,
subcmd->u.transfer.call_1, subcmd->u.transfer.is_call_1_held,
subcmd->u.transfer.call_2, subcmd->u.transfer.is_call_2_held,
sig_pri_transfer_rsp, &xfer_rsp);
sig_pri_lock_private(pri->pvts[chanpos]);
break;
#endif /* defined(HAVE_PRI_TRANSFER) */
#if defined(HAVE_PRI_AOC_EVENTS)
case PRI_SUBCMD_AOC_S:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
sig_pri_aoc_s_from_pri(&subcmd->u.aoc_s, owner,
(pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_S));
ast_channel_unlock(owner);
}
break;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
#if defined(HAVE_PRI_AOC_EVENTS)
case PRI_SUBCMD_AOC_D:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
/* Queue AST_CONTROL_AOC frame on channel */
sig_pri_aoc_d_from_pri(&subcmd->u.aoc_d, owner,
(pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_D));
ast_channel_unlock(owner);
}
break;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
#if defined(HAVE_PRI_AOC_EVENTS)
case PRI_SUBCMD_AOC_E:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
/* Queue AST_CONTROL_AOC frame */
sig_pri_aoc_e_from_pri(&subcmd->u.aoc_e, owner,
(pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_E));
if (owner) {
ast_channel_unlock(owner);
}
break;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
#if defined(HAVE_PRI_AOC_EVENTS)
case PRI_SUBCMD_AOC_CHARGING_REQ:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
sig_pri_aoc_request_from_pri(&subcmd->u.aoc_request, pri->pvts[chanpos],
call_rsp);
ast_channel_unlock(owner);
}
break;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
#if defined(HAVE_PRI_AOC_EVENTS)
case PRI_SUBCMD_AOC_CHARGING_REQ_RSP:
/*
* An AOC request response may contain an AOC-S rate list.
* If this is the case handle this just like we
* would an incoming AOC-S msg.
*/
if (subcmd->u.aoc_request_response.valid_aoc_s) {
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
sig_pri_aoc_s_from_pri(&subcmd->u.aoc_request_response.aoc_s, owner,
(pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_S));
ast_channel_unlock(owner);
}
}
break;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
#if defined(HAVE_PRI_MCID)
case PRI_SUBCMD_MCID_REQ:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
sig_pri_mcid_event(pri, &subcmd->u.mcid_req, owner);
if (owner) {
ast_channel_unlock(owner);
}
break;
#endif /* defined(HAVE_PRI_MCID) */
#if defined(HAVE_PRI_MCID)
case PRI_SUBCMD_MCID_RSP:
/* Ignore for now. */
break;
#endif /* defined(HAVE_PRI_MCID) */
default:
ast_debug(2,
"Unknown call subcommand(%d) in %s event on channel %d/%d on span %d.\n",
subcmd->cmd, pri_event2str(event_id), PRI_SPAN(channel),
PRI_CHANNEL(channel), pri->span);
break;
}
}
}
| int sig_pri_hangup | ( | struct sig_pri_chan * | p, |
| struct ast_channel * | ast | ||
| ) |
Definition at line 5855 of file sig_pri.c.
References sig_pri_chan::alerting, sig_pri_chan::alreadyhungup, sig_pri_chan::aoc_e, sig_pri_chan::aoc_s_request_invoke_id_valid, ast_atomic_fetchadd_int(), ast_log(), sig_pri_chan::call, cause, sig_pri_chan::channel, sig_pri_chan::cid_name, sig_pri_chan::cid_num, sig_pri_chan::cid_subaddr, sig_pri_chan::exten, ast_channel::hangupcause, sig_pri_chan::holding_aoce, sig_pri_chan::is_call_waiting, LOG_DEBUG, LOG_WARNING, sig_pri_span::num_call_waiting_calls, sig_pri_chan::outgoing, sig_pri_chan::owner, pbx_builtin_getvar_helper(), sig_pri_span::pri, sig_pri_chan::pri, pri_grab(), pri_rel(), sig_pri_chan::proceeding, sig_pri_chan::progress, sig_pri_chan::setup_ack, sig_pri_set_dialing(), sig_pri_set_digital(), sig_pri_span_devstate_changed(), sig_pri_span::span, ast_channel::tech_pvt, sig_pri_chan::user_tag, and sig_pri_chan::waiting_for_aoce.
Referenced by dahdi_hangup().
{
int res;
#ifdef SUPPORT_USERUSER
const char *useruser = pbx_builtin_getvar_helper(ast, "USERUSERINFO");
#endif
ast_log(LOG_DEBUG, "%s %d\n", __FUNCTION__, p->channel);
if (!ast->tech_pvt) {
ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
return 0;
}
p->owner = NULL;
p->outgoing = 0;
sig_pri_set_digital(p, 0); /* push up to parent for EC*/
#if defined(HAVE_PRI_CALL_WAITING)
if (p->is_call_waiting) {
p->is_call_waiting = 0;
ast_atomic_fetchadd_int(&p->pri->num_call_waiting_calls, -1);
}
#endif /* defined(HAVE_PRI_CALL_WAITING) */
p->proceeding = 0;
p->progress = 0;
p->alerting = 0;
p->setup_ack = 0;
p->cid_num[0] = '\0';
p->cid_subaddr[0] = '\0';
p->cid_name[0] = '\0';
p->user_tag[0] = '\0';
p->exten[0] = '\0';
sig_pri_set_dialing(p, 0);
/* Make sure we have a call (or REALLY have a call in the case of a PRI) */
if (!pri_grab(p, p->pri)) {
if (p->call) {
if (p->alreadyhungup) {
ast_log(LOG_DEBUG, "Already hungup... Calling hangup once, and clearing call\n");
#ifdef SUPPORT_USERUSER
pri_call_set_useruser(p->call, useruser);
#endif
#if defined(HAVE_PRI_AOC_EVENTS)
if (p->holding_aoce) {
pri_aoc_e_send(p->pri->pri, p->call, &p->aoc_e);
}
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
pri_hangup(p->pri->pri, p->call, -1);
p->call = NULL;
} else {
const char *cause = pbx_builtin_getvar_helper(ast,"PRI_CAUSE");
int icause = ast->hangupcause ? ast->hangupcause : -1;
ast_log(LOG_DEBUG, "Not yet hungup... Calling hangup once with icause, and clearing call\n");
#ifdef SUPPORT_USERUSER
pri_call_set_useruser(p->call, useruser);
#endif
p->alreadyhungup = 1;
if (cause) {
if (atoi(cause))
icause = atoi(cause);
}
#if defined(HAVE_PRI_AOC_EVENTS)
if (p->holding_aoce) {
pri_aoc_e_send(p->pri->pri, p->call, &p->aoc_e);
}
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
pri_hangup(p->pri->pri, p->call, icause);
}
}
sig_pri_span_devstate_changed(p->pri);
pri_rel(p->pri);
res = 0;
} else {
ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->pri->span);
res = -1;
}
#if defined(HAVE_PRI_AOC_EVENTS)
p->aoc_s_request_invoke_id_valid = 0;
p->holding_aoce = 0;
p->waiting_for_aoce = 0;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
ast->tech_pvt = NULL;
return res;
}
| int sig_pri_indicate | ( | struct sig_pri_chan * | p, |
| struct ast_channel * | chan, | ||
| int | condition, | ||
| const void * | data, | ||
| size_t | datalen | ||
| ) |
Definition at line 6467 of file sig_pri.c.
References ast_channel::_softhangup, ast_channel::_state, sig_pri_chan::alerting, sig_pri_span::aoc_passthrough_flag, AST_AOC_D, ast_aoc_decode(), ast_aoc_destroy_decoded(), AST_AOC_E, ast_aoc_get_msg_type(), ast_aoc_get_termination_request(), AST_AOC_REQUEST, AST_AOC_S, AST_CAUSE_CONGESTION, AST_CAUSE_SWITCH_CONGESTION, AST_CAUSE_USER_BUSY, AST_CONTROL_AOC, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_HOLD, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, ast_debug, ast_log(), ast_moh_start(), ast_moh_stop(), ast_setstate(), AST_SOFTHANGUP_DEV, ast_softhangup_nolock(), AST_STATE_RING, AST_STATE_RINGING, AST_STATE_UP, sig_pri_chan::call, ast_channel::connected, sig_pri_chan::digital, ast_channel::hangupcause, ast_party_connected_line::id, LOG_DEBUG, LOG_WARNING, sig_pri_chan::mohinterpret, ast_channel::name, sig_pri_chan::no_b_channel, sig_pri_chan::outgoing, sig_pri_span::pri, sig_pri_chan::pri, pri_grab(), pri_rel(), sig_pri_chan::priindication_oob, sig_pri_chan::prioffset, sig_pri_chan::proceeding, sig_pri_chan::progress, PVT_TO_CHANNEL(), sig_pri_aoc_d_from_ast(), sig_pri_aoc_e_from_ast(), SIG_PRI_AOC_GRANT_D, SIG_PRI_AOC_GRANT_E, SIG_PRI_AOC_GRANT_S, sig_pri_aoc_s_from_ast(), sig_pri_party_id_from_ast(), sig_pri_play_tone(), sig_pri_redirecting_update(), sig_pri_set_dialing(), sig_pri_set_digital(), SIG_PRI_TONE_BUSY, SIG_PRI_TONE_CONGESTION, SIG_PRI_TONE_RINGTONE, sig_pri_span::span, and sig_pri_chan::waiting_for_aoce.
Referenced by dahdi_indicate().
{
int res = -1;
switch (condition) {
case AST_CONTROL_BUSY:
if (p->priindication_oob || p->no_b_channel) {
chan->hangupcause = AST_CAUSE_USER_BUSY;
chan->_softhangup |= AST_SOFTHANGUP_DEV;
res = 0;
} else if (!p->progress && p->pri && !p->outgoing) {
if (p->pri->pri) {
if (!pri_grab(p, p->pri)) {
#ifdef HAVE_PRI_PROG_W_CAUSE
pri_progress_with_cause(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1, PRI_CAUSE_USER_BUSY); /* cause = 17 */
#else
pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
#endif
pri_rel(p->pri);
} else {
ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->pri->span);
}
}
p->progress = 1;
res = sig_pri_play_tone(p, SIG_PRI_TONE_BUSY);
}
break;
case AST_CONTROL_RINGING:
if ((!p->alerting) && p->pri && !p->outgoing && (chan->_state != AST_STATE_UP)) {
if (p->pri->pri) {
if (!pri_grab(p, p->pri)) {
pri_acknowledge(p->pri->pri,p->call, PVT_TO_CHANNEL(p),
p->no_b_channel || p->digital ? 0 : 1);
pri_rel(p->pri);
} else {
ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->pri->span);
}
}
p->alerting = 1;
}
res = sig_pri_play_tone(p, SIG_PRI_TONE_RINGTONE);
if (chan->_state != AST_STATE_UP) {
if (chan->_state != AST_STATE_RING)
ast_setstate(chan, AST_STATE_RINGING);
}
break;
case AST_CONTROL_PROCEEDING:
ast_debug(1,"Received AST_CONTROL_PROCEEDING on %s\n",chan->name);
if (!p->proceeding && p->pri && !p->outgoing) {
if (p->pri->pri) {
if (!pri_grab(p, p->pri)) {
pri_proceeding(p->pri->pri,p->call, PVT_TO_CHANNEL(p),
p->no_b_channel || p->digital ? 0 : 1);
p->proceeding = 1;
if (!p->no_b_channel && !p->digital) {
sig_pri_set_dialing(p, 0);
}
pri_rel(p->pri);
} else {
ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->pri->span);
}
}
}
/* don't continue in ast_indicate */
res = 0;
break;
case AST_CONTROL_PROGRESS:
ast_debug(1,"Received AST_CONTROL_PROGRESS on %s\n",chan->name);
sig_pri_set_digital(p, 0); /* Digital-only calls isn't allowing any inband progress messages */
if (!p->progress && !p->alerting && p->pri && !p->outgoing && !p->no_b_channel) {
if (p->pri->pri) {
if (!pri_grab(p, p->pri)) {
#ifdef HAVE_PRI_PROG_W_CAUSE
pri_progress_with_cause(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1, -1); /* no cause at all */
#else
pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
#endif
pri_rel(p->pri);
} else {
ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->pri->span);
}
}
p->progress = 1;
}
/* don't continue in ast_indicate */
res = 0;
break;
case AST_CONTROL_CONGESTION:
chan->hangupcause = AST_CAUSE_CONGESTION;
if (p->priindication_oob || p->no_b_channel) {
chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
chan->_softhangup |= AST_SOFTHANGUP_DEV;
res = 0;
} else if (!p->progress && p->pri && !p->outgoing) {
if (p->pri->pri) {
if (!pri_grab(p, p->pri)) {
#ifdef HAVE_PRI_PROG_W_CAUSE
pri_progress_with_cause(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1, PRI_CAUSE_SWITCH_CONGESTION); /* cause = 42 */
#else
pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
#endif
pri_rel(p->pri);
} else {
ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->pri->span);
}
}
p->progress = 1;
res = sig_pri_play_tone(p, SIG_PRI_TONE_CONGESTION);
}
break;
case AST_CONTROL_HOLD:
if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
if (!pri_grab(p, p->pri)) {
res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_HOLD);
pri_rel(p->pri);
} else {
ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->pri->span);
}
} else
ast_moh_start(chan, data, p->mohinterpret);
break;
case AST_CONTROL_UNHOLD:
if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
if (!pri_grab(p, p->pri)) {
res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_RETRIEVAL);
pri_rel(p->pri);
}
} else
ast_moh_stop(chan);
break;
case AST_CONTROL_SRCUPDATE:
res = 0;
break;
case -1:
res = sig_pri_play_tone(p, -1);
break;
case AST_CONTROL_CONNECTED_LINE:
ast_debug(1, "Received AST_CONTROL_CONNECTED_LINE on %s\n", chan->name);
if (p->pri && !pri_grab(p, p->pri)) {
struct pri_party_connected_line connected;
memset(&connected, 0, sizeof(connected));
sig_pri_party_id_from_ast(&connected.id, &chan->connected.id);
pri_connected_line_update(p->pri->pri, p->call, &connected);
pri_rel(p->pri);
}
break;
case AST_CONTROL_REDIRECTING:
ast_debug(1, "Received AST_CONTROL_REDIRECTING on %s\n", chan->name);
if (p->pri && !pri_grab(p, p->pri)) {
sig_pri_redirecting_update(p, chan);
pri_rel(p->pri);
}
break;
case AST_CONTROL_AOC:
#if defined(HAVE_PRI_AOC_EVENTS)
{
struct ast_aoc_decoded *decoded
= ast_aoc_decode((struct ast_aoc_encoded *) data, datalen, chan);
ast_debug(1, "Received AST_CONTROL_AOC on %s\n", chan->name);
if (decoded && p->pri && !pri_grab(p, p->pri)) {
switch (ast_aoc_get_msg_type(decoded)) {
case AST_AOC_S:
if (p->pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_S) {
sig_pri_aoc_s_from_ast(p, decoded);
}
break;
case AST_AOC_D:
if (p->pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_D) {
sig_pri_aoc_d_from_ast(p, decoded);
}
break;
case AST_AOC_E:
if (p->pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_E) {
sig_pri_aoc_e_from_ast(p, decoded);
}
/* if hangup was delayed for this AOC-E msg, waiting_for_aoc
* will be set. A hangup is already occuring via a timeout during
* this delay. Instead of waiting for that timeout to occur, go ahead
* and initiate the softhangup since the delay is no longer necessary */
if (p->waiting_for_aoce) {
p->waiting_for_aoce = 0;
ast_log(LOG_DEBUG,
"Received final AOC-E msg, continue with hangup on %s\n",
chan->name);
ast_softhangup_nolock(chan, AST_SOFTHANGUP_DEV);
}
break;
case AST_AOC_REQUEST:
/* We do not pass through AOC requests, So unless this
* is an AOC termination request it will be ignored */
if (ast_aoc_get_termination_request(decoded)) {
pri_hangup(p->pri->pri, p->call, -1);
}
break;
default:
break;
}
pri_rel(p->pri);
}
ast_aoc_destroy_decoded(decoded);
}
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
break;
}
return res;
}
| static void sig_pri_init_config | ( | struct sig_pri_chan * | pvt, |
| struct sig_pri_span * | pri | ||
| ) | [static] |
Definition at line 1402 of file sig_pri.c.
References ast_copy_string(), sig_pri_span::calls, sig_pri_span::ch_cfg, sig_pri_chan::chan_pvt, sig_pri_span::context, sig_pri_chan::context, sig_pri_span::hidecallerid, sig_pri_chan::hidecallerid, sig_pri_span::hidecalleridname, sig_pri_chan::hidecalleridname, sig_pri_span::immediate, sig_pri_chan::immediate, sig_pri_callback::init_config, sig_pri_span::mohinterpret, sig_pri_chan::mohinterpret, sig_pri_span::priexclusive, sig_pri_chan::priexclusive, sig_pri_span::priindication_oob, sig_pri_chan::priindication_oob, sig_pri_span::stripmsd, sig_pri_chan::stripmsd, sig_pri_span::use_callerid, sig_pri_chan::use_callerid, sig_pri_span::use_callingpres, and sig_pri_chan::use_callingpres.
Referenced by pri_dchannel(), and sig_pri_cw_available().
{
pvt->stripmsd = pri->ch_cfg.stripmsd;
pvt->hidecallerid = pri->ch_cfg.hidecallerid;
pvt->hidecalleridname = pri->ch_cfg.hidecalleridname;
pvt->immediate = pri->ch_cfg.immediate;
pvt->priexclusive = pri->ch_cfg.priexclusive;
pvt->priindication_oob = pri->ch_cfg.priindication_oob;
pvt->use_callerid = pri->ch_cfg.use_callerid;
pvt->use_callingpres = pri->ch_cfg.use_callingpres;
ast_copy_string(pvt->context, pri->ch_cfg.context, sizeof(pvt->context));
ast_copy_string(pvt->mohinterpret, pri->ch_cfg.mohinterpret, sizeof(pvt->mohinterpret));
if (pri->calls->init_config) {
pri->calls->init_config(pvt->chan_pvt, pri);
}
}
| void sig_pri_init_pri | ( | struct sig_pri_span * | pri | ) |
Definition at line 5842 of file sig_pri.c.
References ast_mutex_init, AST_PTHREADT_NULL, sig_pri_span::fds, sig_pri_span::lock, sig_pri_span::master, and SIG_PRI_NUM_DCHANS.
Referenced by dahdi_restart(), and load_module().
{
int i;
memset(pri, 0, sizeof(*pri));
ast_mutex_init(&pri->lock);
pri->master = AST_PTHREADT_NULL;
for (i = 0; i < SIG_PRI_NUM_DCHANS; i++)
pri->fds[i] = -1;
}
| static int sig_pri_is_cis_call | ( | int | channel | ) | [static] |
Definition at line 3484 of file sig_pri.c.
References PRI_CIS_CALL.
Referenced by pri_dchannel().
{
return channel != -1 && (channel & PRI_CIS_CALL);
}
| int sig_pri_load | ( | const char * | cc_type_name | ) |
Load the sig_pri submodule.
| cc_type_name | CC type name to use when looking up agent/monitor. |
| 0 | on success. |
| -1 | on error. |
Definition at line 7942 of file sig_pri.c.
References ao2_container_alloc, sig_pri_cc_monitor_instance_cmp_fn(), sig_pri_cc_monitor_instance_hash_fn(), and sig_pri_cc_type_name.
Referenced by load_module().
{
#if defined(HAVE_PRI_CCSS)
sig_pri_cc_type_name = cc_type_name;
sig_pri_cc_monitors = ao2_container_alloc(37, sig_pri_cc_monitor_instance_hash_fn,
sig_pri_cc_monitor_instance_cmp_fn);
if (!sig_pri_cc_monitors) {
return -1;
}
#endif /* defined(HAVE_PRI_CCSS) */
return 0;
}
| static void sig_pri_lock_owner | ( | struct sig_pri_span * | pri, |
| int | chanpos | ||
| ) | [static] |
Definition at line 1012 of file sig_pri.c.
References ast_channel_trylock, ast_mutex_lock, ast_mutex_unlock, sig_pri_span::lock, sig_pri_chan::owner, PRI_DEADLOCK_AVOIDANCE, and sig_pri_span::pvts.
Referenced by pri_dchannel(), pri_fixup_principle(), pri_queue_frame(), sig_pri_attempt_transfer(), sig_pri_cc_generic_check(), sig_pri_handle_hold(), sig_pri_handle_subcmds(), and sig_pri_send_aoce_termination_request().
{
for (;;) {
if (!pri->pvts[chanpos]->owner) {
/* There is no owner lock to get. */
break;
}
if (!ast_channel_trylock(pri->pvts[chanpos]->owner)) {
/* We got the lock */
break;
}
/* We must unlock the PRI to avoid the possibility of a deadlock */
ast_mutex_unlock(&pri->lock);
PRI_DEADLOCK_AVOIDANCE(pri->pvts[chanpos]);
ast_mutex_lock(&pri->lock);
}
}
| static void sig_pri_lock_private | ( | struct sig_pri_chan * | p | ) | [static] |
Definition at line 277 of file sig_pri.c.
References sig_pri_chan::calls, sig_pri_chan::chan_pvt, and sig_pri_callback::lock_private.
Referenced by pri_dchannel(), pri_fixup_principle(), pri_send_callrerouting_facility_exec(), pri_send_keypad_facility_exec(), pri_ss_thread(), sig_pri_attempt_transfer(), sig_pri_handle_hold(), sig_pri_handle_retrieve(), and sig_pri_handle_subcmds().
{
if (p->calls->lock_private)
p->calls->lock_private(p->chan_pvt);
}
| static void sig_pri_make_cc_dialstring | ( | struct sig_pri_chan * | p, |
| char * | buf, | ||
| size_t | buf_size | ||
| ) | [static] |
Definition at line 165 of file sig_pri.c.
References ast_log(), sig_pri_chan::calls, sig_pri_chan::chan_pvt, LOG_ERROR, and sig_pri_callback::make_cc_dialstring.
Referenced by sig_pri_cc_available().
{
if (p->calls->make_cc_dialstring) {
p->calls->make_cc_dialstring(p->chan_pvt, buf, buf_size);
} else {
ast_log(LOG_ERROR, "make_cc_dialstring callback not defined\n");
buf[0] = '\0';
}
}
| static void sig_pri_mcid_event | ( | struct sig_pri_span * | pri, |
| const struct pri_subcmd_mcid_req * | mcid, | ||
| struct ast_channel * | owner | ||
| ) | [static] |
Definition at line 1900 of file sig_pri.c.
References ast_free, ast_manager_event_multichan, ast_party_id_free(), ast_party_id_init(), ast_str_append(), ast_str_buffer(), ast_str_create(), ast_channel::connected, EVENT_FLAG_CALL, ast_party_connected_line::id, ast_channel::name, sig_pri_event_party_id(), sig_pri_party_id_convert(), and ast_channel::uniqueid.
Referenced by sig_pri_handle_subcmds().
{
struct ast_channel *chans[1];
struct ast_str *msg;
struct ast_party_id party;
msg = ast_str_create(4096);
if (!msg) {
return;
}
if (owner) {
/* The owner channel is present. */
ast_str_append(&msg, 0, "Channel: %s\r\n", owner->name);
ast_str_append(&msg, 0, "UniqueID: %s\r\n", owner->uniqueid);
sig_pri_event_party_id(&msg, "CallerID", &owner->connected.id);
} else {
/*
* Since we no longer have an owner channel,
* we have to use the caller information supplied by libpri.
*/
ast_party_id_init(&party);
sig_pri_party_id_convert(&party, &mcid->originator, pri);
sig_pri_event_party_id(&msg, "CallerID", &party);
ast_party_id_free(&party);
}
/* Always use libpri's called party information. */
ast_party_id_init(&party);
sig_pri_party_id_convert(&party, &mcid->answerer, pri);
sig_pri_event_party_id(&msg, "ConnectedID", &party);
ast_party_id_free(&party);
chans[0] = owner;
ast_manager_event_multichan(EVENT_FLAG_CALL, "MCID", owner ? 1 : 0, chans, "%s",
ast_str_buffer(msg));
ast_free(msg);
}
| static int sig_pri_msn_match | ( | const char * | msn_patterns, |
| const char * | exten | ||
| ) | [static] |
Definition at line 1799 of file sig_pri.c.
References ast_extension_match(), ast_strdupa, ast_strip(), and ast_strlen_zero().
Referenced by pri_dchannel().
{
char *pattern;
char *msn_list;
char *list_tail;
msn_list = ast_strdupa(msn_patterns);
list_tail = NULL;
pattern = strtok_r(msn_list, ",", &list_tail);
while (pattern) {
pattern = ast_strip(pattern);
if (!ast_strlen_zero(pattern) && ast_extension_match(pattern, exten)) {
/* Extension matched the pattern. */
return 1;
}
pattern = strtok_r(NULL, ",", &list_tail);
}
/* Did not match any pattern in the list. */
return 0;
}
| static void sig_pri_mwi_cache_update | ( | struct sig_pri_span * | pri | ) | [static] |
Definition at line 6914 of file sig_pri.c.
References ARRAY_LEN, ast_event_destroy(), ast_event_get_cached(), ast_event_get_ie_uint(), AST_EVENT_IE_CONTEXT, AST_EVENT_IE_END, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_MWI, sig_pri_mbox::context, sig_pri_span::mbox, sig_pri_mbox::number, sig_pri_send_mwi_indication(), and sig_pri_mbox::sub.
Referenced by sig_pri_start_pri().
{
int idx;
int num_messages;
struct ast_event *event;
for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) {
if (!pri->mbox[idx].sub) {
/* There are no more mailboxes on this span. */
break;
}
event = ast_event_get_cached(AST_EVENT_MWI,
AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, pri->mbox[idx].number,
AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, pri->mbox[idx].context,
AST_EVENT_IE_END);
if (!event) {
/* No cached event for this mailbox. */
continue;
}
num_messages = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
sig_pri_send_mwi_indication(pri, pri->mbox[idx].number, pri->mbox[idx].context,
num_messages);
ast_event_destroy(event);
}
}
| static void sig_pri_mwi_event_cb | ( | const struct ast_event * | event, |
| void * | userdata | ||
| ) | [static] |
Definition at line 6884 of file sig_pri.c.
References ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_CONTEXT, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_NEWMSGS, ast_strlen_zero(), sig_pri_span::pri, and sig_pri_send_mwi_indication().
Referenced by sig_pri_start_pri().
{
struct sig_pri_span *pri = userdata;
const char *mbox_context;
const char *mbox_number;
int num_messages;
mbox_number = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
if (ast_strlen_zero(mbox_number)) {
return;
}
mbox_context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
if (ast_strlen_zero(mbox_context)) {
return;
}
num_messages = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
sig_pri_send_mwi_indication(pri, mbox_number, mbox_context, num_messages);
}
| static struct ast_channel* sig_pri_new_ast_channel | ( | struct sig_pri_chan * | p, |
| int | state, | ||
| int | ulaw, | ||
| int | transfercapability, | ||
| char * | exten, | ||
| const struct ast_channel * | requestor | ||
| ) | [static, read] |
Definition at line 864 of file sig_pri.c.
References sig_pri_chan::alreadyhungup, ast_mutex_lock, ast_mutex_unlock, AST_TRANS_CAP_DIGITAL, ast_transfercapability2str(), sig_pri_chan::calls, sig_pri_chan::chan_pvt, sig_pri_chan::isidlecall, sig_pri_span::lock, sig_pri_callback::new_ast_channel, sig_pri_chan::owner, pbx_builtin_setvar_helper(), sig_pri_chan::pri, sig_pri_set_digital(), sig_pri_span_devstate_changed(), and ast_channel::transfercapability.
Referenced by pri_dchannel(), and sig_pri_request().
{
struct ast_channel *c;
if (p->calls->new_ast_channel)
c = p->calls->new_ast_channel(p->chan_pvt, state, ulaw, exten, requestor);
else
return NULL;
if (!p->owner)
p->owner = c;
p->isidlecall = 0;
p->alreadyhungup = 0;
c->transfercapability = transfercapability;
pbx_builtin_setvar_helper(c, "TRANSFERCAPABILITY",
ast_transfercapability2str(transfercapability));
if (transfercapability & AST_TRANS_CAP_DIGITAL) {
sig_pri_set_digital(p, 1);
}
if (p->pri) {
ast_mutex_lock(&p->pri->lock);
sig_pri_span_devstate_changed(p->pri);
ast_mutex_unlock(&p->pri->lock);
}
return c;
}
| static void sig_pri_open_media | ( | struct sig_pri_chan * | p | ) | [static] |
Definition at line 901 of file sig_pri.c.
References sig_pri_chan::calls, sig_pri_chan::chan_pvt, sig_pri_chan::no_b_channel, and sig_pri_callback::open_media.
Referenced by pri_dchannel(), pri_fixup_principle(), and sig_pri_answer().
{
if (p->no_b_channel) {
return;
}
if (p->calls->open_media) {
p->calls->open_media(p->chan_pvt);
}
}
| static void sig_pri_party_id_convert | ( | struct ast_party_id * | ast_id, |
| const struct pri_party_id * | pri_id, | ||
| struct sig_pri_span * | pri | ||
| ) | [static] |
Definition at line 1745 of file sig_pri.c.
References ast_party_id::name, ast_party_id::number, sig_pri_party_name_convert(), sig_pri_party_number_convert(), sig_pri_set_subaddress(), and ast_party_id::subaddress.
Referenced by sig_pri_handle_subcmds(), sig_pri_mcid_event(), and sig_pri_redirecting_convert().
{
if (pri_id->name.valid) {
sig_pri_party_name_convert(&ast_id->name, &pri_id->name);
}
if (pri_id->number.valid) {
sig_pri_party_number_convert(&ast_id->number, &pri_id->number, pri);
}
#if defined(HAVE_PRI_SUBADDR)
if (pri_id->subaddress.valid) {
sig_pri_set_subaddress(&ast_id->subaddress, &pri_id->subaddress);
}
#endif /* defined(HAVE_PRI_SUBADDR) */
}
| static void sig_pri_party_id_from_ast | ( | struct pri_party_id * | pri_id, |
| const struct ast_party_id * | ast_id | ||
| ) | [static] |
Definition at line 790 of file sig_pri.c.
References ast_party_id::name, ast_party_id::number, sig_pri_party_name_from_ast(), sig_pri_party_number_from_ast(), sig_pri_party_subaddress_from_ast(), and ast_party_id::subaddress.
Referenced by sig_pri_indicate(), and sig_pri_redirecting_update().
{
sig_pri_party_name_from_ast(&pri_id->name, &ast_id->name);
sig_pri_party_number_from_ast(&pri_id->number, &ast_id->number);
#if defined(HAVE_PRI_SUBADDR)
sig_pri_party_subaddress_from_ast(&pri_id->subaddress, &ast_id->subaddress);
#endif /* defined(HAVE_PRI_SUBADDR) */
}
| static void sig_pri_party_name_convert | ( | struct ast_party_name * | ast_name, |
| const struct pri_party_name * | pri_name | ||
| ) | [static] |
Definition at line 1698 of file sig_pri.c.
References ast_strdup, ast_party_name::char_set, ast_party_name::presentation, pri_to_ast_char_set(), pri_to_ast_presentation(), ast_party_name::str, and ast_party_name::valid.
Referenced by sig_pri_party_id_convert().
{
ast_name->str = ast_strdup(pri_name->str);
ast_name->char_set = pri_to_ast_char_set(pri_name->char_set);
ast_name->presentation = pri_to_ast_presentation(pri_name->presentation);
ast_name->valid = 1;
}
| static void sig_pri_party_name_from_ast | ( | struct pri_party_name * | pri_name, |
| const struct ast_party_name * | ast_name | ||
| ) | [static] |
Definition at line 740 of file sig_pri.c.
References ast_copy_string(), ast_strlen_zero(), ast_to_pri_char_set(), ast_to_pri_presentation(), ast_party_name::char_set, ast_party_name::presentation, ast_party_name::str, and ast_party_name::valid.
Referenced by sig_pri_party_id_from_ast().
{
if (!ast_name->valid) {
return;
}
pri_name->valid = 1;
pri_name->presentation = ast_to_pri_presentation(ast_name->presentation);
pri_name->char_set = ast_to_pri_char_set(ast_name->char_set);
if (!ast_strlen_zero(ast_name->str)) {
ast_copy_string(pri_name->str, ast_name->str, sizeof(pri_name->str));
}
}
| static void sig_pri_party_number_convert | ( | struct ast_party_number * | ast_number, |
| const struct pri_party_number * | pri_number, | ||
| struct sig_pri_span * | pri | ||
| ) | [static] |
Definition at line 1720 of file sig_pri.c.
References apply_plan_to_number(), AST_MAX_EXTENSION, ast_strdup, ast_party_number::plan, ast_party_number::presentation, pri_to_ast_presentation(), ast_party_number::str, and ast_party_number::valid.
Referenced by sig_pri_party_id_convert().
{
char number[AST_MAX_EXTENSION];
apply_plan_to_number(number, sizeof(number), pri, pri_number->str, pri_number->plan);
ast_number->str = ast_strdup(number);
ast_number->plan = pri_number->plan;
ast_number->presentation = pri_to_ast_presentation(pri_number->presentation);
ast_number->valid = 1;
}
| static void sig_pri_party_number_from_ast | ( | struct pri_party_number * | pri_number, |
| const struct ast_party_number * | ast_number | ||
| ) | [static] |
Definition at line 765 of file sig_pri.c.
References ast_copy_string(), ast_strlen_zero(), ast_to_pri_presentation(), ast_party_number::plan, ast_party_number::presentation, ast_party_number::str, and ast_party_number::valid.
Referenced by sig_pri_party_id_from_ast().
{
if (!ast_number->valid) {
return;
}
pri_number->valid = 1;
pri_number->presentation = ast_to_pri_presentation(ast_number->presentation);
pri_number->plan = ast_number->plan;
if (!ast_strlen_zero(ast_number->str)) {
ast_copy_string(pri_number->str, ast_number->str, sizeof(pri_number->str));
}
}
| static void sig_pri_party_subaddress_from_ast | ( | struct pri_party_subaddress * | pri_subaddress, |
| const struct ast_party_subaddress * | ast_subaddress | ||
| ) | [static] |
Definition at line 700 of file sig_pri.c.
References ast_copy_string(), ast_pri_pack_hex_string(), ast_strlen_zero(), ast_party_subaddress::str, ast_party_subaddress::type, and ast_party_subaddress::valid.
Referenced by sig_pri_call(), and sig_pri_party_id_from_ast().
{
if (ast_subaddress->valid && !ast_strlen_zero(ast_subaddress->str)) {
pri_subaddress->type = ast_subaddress->type;
if (!ast_subaddress->type) {
/* 0 = NSAP */
ast_copy_string((char *) pri_subaddress->data, ast_subaddress->str,
sizeof(pri_subaddress->data));
pri_subaddress->length = strlen((char *) pri_subaddress->data);
pri_subaddress->odd_even_indicator = 0;
pri_subaddress->valid = 1;
} else {
/* 2 = User Specified */
/*
* Copy HexString to packed HexData,
* if odd length then right pad trailing byte with 0
*/
int length = ast_pri_pack_hex_string(pri_subaddress->data,
ast_subaddress->str, sizeof(pri_subaddress->data));
pri_subaddress->length = length;
pri_subaddress->odd_even_indicator = (length & 1);
pri_subaddress->valid = 1;
}
}
}
| static int sig_pri_play_tone | ( | struct sig_pri_chan * | p, |
| enum sig_pri_tone | tone | ||
| ) | [static] |
Definition at line 856 of file sig_pri.c.
References sig_pri_chan::calls, sig_pri_chan::chan_pvt, and sig_pri_callback::play_tone.
Referenced by pri_ss_thread(), and sig_pri_indicate().
| static void sig_pri_redirecting_convert | ( | struct ast_party_redirecting * | ast_redirecting, |
| const struct pri_party_redirecting * | pri_redirecting, | ||
| const struct ast_party_redirecting * | ast_guide, | ||
| struct sig_pri_span * | pri | ||
| ) | [static] |
Definition at line 1775 of file sig_pri.c.
References ast_party_redirecting_set_init(), ast_party_redirecting::count, ast_party_redirecting::from, pri_to_ast_reason(), ast_party_redirecting::reason, sig_pri_party_id_convert(), and ast_party_redirecting::to.
Referenced by sig_pri_handle_subcmds().
{
ast_party_redirecting_set_init(ast_redirecting, ast_guide);
sig_pri_party_id_convert(&ast_redirecting->from, &pri_redirecting->from, pri);
sig_pri_party_id_convert(&ast_redirecting->to, &pri_redirecting->to, pri);
ast_redirecting->count = pri_redirecting->count;
ast_redirecting->reason = pri_to_ast_reason(pri_redirecting->reason);
}
| static void sig_pri_redirecting_update | ( | struct sig_pri_chan * | pvt, |
| struct ast_channel * | ast | ||
| ) | [static] |
Definition at line 811 of file sig_pri.c.
References ast_to_pri_reason(), sig_pri_chan::call, ast_party_redirecting::count, ast_party_redirecting::from, sig_pri_span::pri, sig_pri_chan::pri, ast_party_redirecting::reason, ast_channel::redirecting, sig_pri_party_id_from_ast(), and ast_party_redirecting::to.
Referenced by sig_pri_call(), and sig_pri_indicate().
{
struct pri_party_redirecting pri_redirecting;
/*! \todo XXX Original called data can be put in a channel data store that is inherited. */
memset(&pri_redirecting, 0, sizeof(pri_redirecting));
sig_pri_party_id_from_ast(&pri_redirecting.from, &ast->redirecting.from);
sig_pri_party_id_from_ast(&pri_redirecting.to, &ast->redirecting.to);
pri_redirecting.count = ast->redirecting.count;
pri_redirecting.reason = ast_to_pri_reason(ast->redirecting.reason);
pri_redirecting_update(pvt->pri->pri, pvt->call, &pri_redirecting);
}
| struct ast_channel* sig_pri_request | ( | struct sig_pri_chan * | p, |
| enum sig_pri_law | law, | ||
| const struct ast_channel * | requestor, | ||
| int | transfercapability | ||
| ) | [read] |
Definition at line 912 of file sig_pri.c.
References ast_log(), AST_STATE_RESERVED, sig_pri_chan::channel, sig_pri_chan::exten, LOG_DEBUG, sig_pri_chan::outgoing, and sig_pri_new_ast_channel().
Referenced by dahdi_request(), and pri_dchannel().
{
struct ast_channel *ast;
ast_log(LOG_DEBUG, "%s %d\n", __FUNCTION__, p->channel);
p->outgoing = 1;
ast = sig_pri_new_ast_channel(p, AST_STATE_RESERVED, law, transfercapability, p->exten, requestor);
if (!ast) {
p->outgoing = 0;
}
return ast;
}
| static void sig_pri_send_aoce_termination_request | ( | struct sig_pri_span * | pri, |
| int | chanpos, | ||
| unsigned int | ms | ||
| ) | [static] |
Definition at line 3429 of file sig_pri.c.
References ast_aoc_create(), ast_aoc_destroy_decoded(), ast_aoc_destroy_encoded(), ast_aoc_encode(), AST_AOC_REQUEST, AST_AOC_REQUEST_E, ast_aoc_set_termination_request(), ast_channel_setwhentohangup_tv(), ast_channel_unlock, AST_CONTROL_AOC, ast_log(), ast_queue_control_data(), AST_SOFTHANGUP_DEV, ast_softhangup_nolock(), LOG_DEBUG, ast_channel::name, sig_pri_chan::owner, sig_pri_span::pvts, sig_pri_lock_owner(), and sig_pri_chan::waiting_for_aoce.
Referenced by pri_dchannel().
{
struct sig_pri_chan *pvt;
struct ast_aoc_decoded *decoded = NULL;
struct ast_aoc_encoded *encoded = NULL;
size_t encoded_size;
struct timeval whentohangup = { 0, };
sig_pri_lock_owner(pri, chanpos);
pvt = pri->pvts[chanpos];
if (!pvt->owner) {
return;
}
if (!(decoded = ast_aoc_create(AST_AOC_REQUEST, 0, AST_AOC_REQUEST_E))) {
ast_softhangup_nolock(pvt->owner, AST_SOFTHANGUP_DEV);
goto cleanup_termination_request;
}
ast_aoc_set_termination_request(decoded);
if (!(encoded = ast_aoc_encode(decoded, &encoded_size, pvt->owner))) {
ast_softhangup_nolock(pvt->owner, AST_SOFTHANGUP_DEV);
goto cleanup_termination_request;
}
/* convert ms to timeval */
whentohangup.tv_usec = (ms % 1000) * 1000;
whentohangup.tv_sec = ms / 1000;
if (ast_queue_control_data(pvt->owner, AST_CONTROL_AOC, encoded, encoded_size)) {
ast_softhangup_nolock(pvt->owner, AST_SOFTHANGUP_DEV);
goto cleanup_termination_request;
}
pvt->waiting_for_aoce = 1;
ast_channel_setwhentohangup_tv(pvt->owner, whentohangup);
ast_log(LOG_DEBUG, "Delaying hangup on %s for aoc-e msg\n", pvt->owner->name);
cleanup_termination_request:
ast_channel_unlock(pvt->owner);
ast_aoc_destroy_decoded(decoded);
ast_aoc_destroy_encoded(encoded);
}
| static void sig_pri_send_mwi_indication | ( | struct sig_pri_span * | pri, |
| const char * | mbox_number, | ||
| const char * | mbox_context, | ||
| int | num_messages | ||
| ) | [static] |
Definition at line 6854 of file sig_pri.c.
References ast_copy_string(), ast_debug, ast_mutex_lock, ast_mutex_unlock, sig_pri_span::lock, and sig_pri_span::pri.
Referenced by sig_pri_mwi_cache_update(), and sig_pri_mwi_event_cb().
{
struct pri_party_id mailbox;
ast_debug(1, "Send MWI indication for %s@%s num_messages:%d\n", mbox_number,
mbox_context, num_messages);
memset(&mailbox, 0, sizeof(mailbox));
mailbox.number.valid = 1;
mailbox.number.presentation = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
mailbox.number.plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_UNKNOWN;
ast_copy_string(mailbox.number.str, mbox_number, sizeof(mailbox.number.str));
ast_mutex_lock(&pri->lock);
pri_mwi_indicate(pri->pri, &mailbox, 1 /* speech */, num_messages, NULL, NULL, -1, 0);
ast_mutex_unlock(&pri->lock);
}
| static void sig_pri_set_alarm | ( | struct sig_pri_chan * | p, |
| int | in_alarm | ||
| ) | [static] |
Definition at line 147 of file sig_pri.c.
References sig_pri_chan::calls, sig_pri_chan::chan_pvt, sig_pri_chan::inalarm, and sig_pri_callback::set_alarm.
Referenced by pri_dchannel(), and sig_pri_chan_alarm_notify().
| static void sig_pri_set_caller_id | ( | struct sig_pri_chan * | p | ) | [static] |
Definition at line 203 of file sig_pri.c.
References ast_party_caller::ani, ast_party_caller::ani2, ast_party_caller_init(), ast_strlen_zero(), sig_pri_chan::callingpres, sig_pri_chan::calls, sig_pri_chan::chan_pvt, sig_pri_chan::cid_ani, sig_pri_chan::cid_ani2, sig_pri_chan::cid_name, sig_pri_chan::cid_num, sig_pri_chan::cid_subaddr, sig_pri_chan::cid_ton, ast_party_caller::id, ast_party_id::name, ast_party_id::number, ast_party_number::plan, ast_party_number::presentation, ast_party_name::presentation, sig_pri_callback::set_callerid, ast_party_subaddress::str, ast_party_number::str, ast_party_name::str, ast_party_id::subaddress, ast_party_id::tag, sig_pri_chan::user_tag, ast_party_subaddress::valid, ast_party_number::valid, and ast_party_name::valid.
Referenced by pri_dchannel(), and sig_pri_handle_subcmds().
{
struct ast_party_caller caller;
if (p->calls->set_callerid) {
ast_party_caller_init(&caller);
caller.id.name.str = p->cid_name;
caller.id.name.presentation = p->callingpres;
caller.id.name.valid = 1;
caller.id.number.str = p->cid_num;
caller.id.number.plan = p->cid_ton;
caller.id.number.presentation = p->callingpres;
caller.id.number.valid = 1;
if (!ast_strlen_zero(p->cid_subaddr)) {
caller.id.subaddress.valid = 1;
//caller.id.subaddress.type = 0;/* nsap */
//caller.id.subaddress.odd_even_indicator = 0;
caller.id.subaddress.str = p->cid_subaddr;
}
caller.id.tag = p->user_tag;
caller.ani.number.str = p->cid_ani;
//caller.ani.number.plan = p->xxx;
//caller.ani.number.presentation = p->xxx;
caller.ani.number.valid = 1;
caller.ani2 = p->cid_ani2;
p->calls->set_callerid(p->chan_pvt, &caller);
}
}
| static void sig_pri_set_dialing | ( | struct sig_pri_chan * | p, |
| int | is_dialing | ||
| ) | [static] |
Definition at line 132 of file sig_pri.c.
References sig_pri_chan::calls, sig_pri_chan::chan_pvt, and sig_pri_callback::set_dialing.
Referenced by pri_dchannel(), sig_pri_answer(), sig_pri_call(), sig_pri_hangup(), and sig_pri_indicate().
{
if (p->calls->set_dialing) {
p->calls->set_dialing(p->chan_pvt, is_dialing);
}
}
| static void sig_pri_set_digital | ( | struct sig_pri_chan * | p, |
| int | is_digital | ||
| ) | [static] |
Definition at line 139 of file sig_pri.c.
References sig_pri_chan::calls, sig_pri_chan::chan_pvt, sig_pri_chan::digital, and sig_pri_callback::set_digital.
Referenced by sig_pri_call(), sig_pri_hangup(), sig_pri_indicate(), and sig_pri_new_ast_channel().
{
p->digital = is_digital;
if (p->calls->set_digital) {
p->calls->set_digital(p->chan_pvt, is_digital);
}
}
| static void sig_pri_set_dnid | ( | struct sig_pri_chan * | p, |
| const char * | dnid | ||
| ) | [static] |
Definition at line 247 of file sig_pri.c.
References sig_pri_chan::calls, sig_pri_chan::chan_pvt, and sig_pri_callback::set_dnid.
Referenced by pri_dchannel().
| static int sig_pri_set_echocanceller | ( | struct sig_pri_chan * | p, |
| int | enable | ||
| ) | [static] |
Definition at line 842 of file sig_pri.c.
References sig_pri_chan::calls, sig_pri_chan::chan_pvt, and sig_pri_callback::set_echocanceller.
Referenced by pri_dchannel(), and pri_ss_thread().
{
if (p->calls->set_echocanceller)
return p->calls->set_echocanceller(p->chan_pvt, enable);
else
return -1;
}
| static void sig_pri_set_rdnis | ( | struct sig_pri_chan * | p, |
| const char * | rdnis | ||
| ) | [static] |
Definition at line 264 of file sig_pri.c.
References sig_pri_chan::calls, sig_pri_chan::chan_pvt, and sig_pri_callback::set_rdnis.
Referenced by pri_dchannel().
| static void sig_pri_set_subaddress | ( | struct ast_party_subaddress * | ast_subaddress, |
| const struct pri_party_subaddress * | pri_subaddress | ||
| ) | [static] |
Definition at line 578 of file sig_pri.c.
References ast_free, ast_malloc, ast_party_subaddress_init(), ast_strdup, len(), ast_party_subaddress::odd_even_indicator, ast_party_subaddress::str, ast_party_subaddress::type, and ast_party_subaddress::valid.
Referenced by pri_dchannel(), and sig_pri_party_id_convert().
{
char *cnum, *ptr;
int x, len;
if (ast_subaddress->str) {
ast_free(ast_subaddress->str);
}
if (pri_subaddress->length <= 0) {
ast_party_subaddress_init(ast_subaddress);
return;
}
if (!pri_subaddress->type) {
/* NSAP */
ast_subaddress->str = ast_strdup((char *) pri_subaddress->data);
} else {
/* User Specified */
if (!(cnum = ast_malloc(2 * pri_subaddress->length + 1))) {
ast_party_subaddress_init(ast_subaddress);
return;
}
ptr = cnum;
len = pri_subaddress->length - 1; /* -1 account for zero based indexing */
for (x = 0; x < len; ++x) {
ptr += sprintf(ptr, "%02x", pri_subaddress->data[x]);
}
if (pri_subaddress->odd_even_indicator) {
/* ODD */
sprintf(ptr, "%01x", (pri_subaddress->data[len]) >> 4);
} else {
/* EVEN */
sprintf(ptr, "%02x", pri_subaddress->data[len]);
}
ast_subaddress->str = cnum;
}
ast_subaddress->type = pri_subaddress->type;
ast_subaddress->odd_even_indicator = pri_subaddress->odd_even_indicator;
ast_subaddress->valid = 1;
}
| static void sig_pri_sort_pri_chans | ( | struct sig_pri_span * | pri | ) | [static] |
Definition at line 7010 of file sig_pri.c.
References sig_pri_span::numchans, sig_pri_span::pvts, and sig_pri_cmp_pri_chans().
Referenced by sig_pri_start_pri().
{
qsort(&pri->pvts, pri->numchans, sizeof(pri->pvts[0]), sig_pri_cmp_pri_chans);
}
| static void sig_pri_span_devstate_changed | ( | struct sig_pri_span * | pri | ) | [static] |
Definition at line 187 of file sig_pri.c.
References sig_pri_span::calls, and sig_pri_callback::update_span_devstate.
Referenced by pri_dchannel(), sig_pri_handle_hold(), sig_pri_handle_retrieve(), sig_pri_hangup(), and sig_pri_new_ast_channel().
{
if (pri->calls->update_span_devstate) {
pri->calls->update_span_devstate(pri);
}
}
| int sig_pri_start_pri | ( | struct sig_pri_span * | pri | ) |
Definition at line 7015 of file sig_pri.c.
References ARRAY_LEN, AST_EVENT_IE_CONTEXT, AST_EVENT_IE_END, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_MWI, ast_event_subscribe(), ast_event_unsubscribe(), ast_log(), ast_mutex_init, ast_pthread_create_background, ast_str_alloca, ast_str_buffer(), ast_str_set(), ast_strip(), ast_strlen_zero(), sig_pri_span::cc_ptmp_recall_mode, sig_pri_span::cc_qsig_signaling_link_req, sig_pri_span::cc_qsig_signaling_link_rsp, sig_pri_mbox::context, DAHDI_CHAN_MAPPING_LOGICAL, DAHDI_OVERLAPDIAL_OUTGOING, sig_pri_span::dchans, sig_pri_span::enable_service_message_support, errno, sig_pri_span::fds, sig_pri_span::inbanddisconnect, sig_pri_span::lock, LOG_ERROR, sig_pri_span::master, sig_pri_span::mbox, sig_pri_span::mwi_mailboxes, sig_pri_span::nodetype, sig_pri_span::nsf, sig_pri_mbox::number, sig_pri_span::overlapdial, sig_pri_span::pri, pri_dchannel(), sig_pri_span::pritimers, sig_pri_span::qsigchannelmapping, sig_pri_span::resetpos, sig_pri_span::sig, SIG_BRI, SIG_BRI_PTMP, sig_pri_cc_type_name, SIG_PRI_DEBUG_DEFAULT, sig_pri_mwi_cache_update(), sig_pri_mwi_event_cb(), SIG_PRI_NUM_DCHANS, sig_pri_sort_pri_chans(), sig_pri_span::span, strsep(), sig_pri_mbox::sub, and sig_pri_span::switchtype.
Referenced by setup_dahdi_int().
{
int x;
int i;
#if defined(HAVE_PRI_MWI)
char *saveptr;
char *mbox_number;
char *mbox_context;
struct ast_str *mwi_description = ast_str_alloca(64);
#endif /* defined(HAVE_PRI_MWI) */
#if defined(HAVE_PRI_MWI)
/* Prepare the mbox[] for use. */
for (i = 0; i < ARRAY_LEN(pri->mbox); ++i) {
if (pri->mbox[i].sub) {
pri->mbox[i].sub = ast_event_unsubscribe(pri->mbox[i].sub);
}
}
#endif /* defined(HAVE_PRI_MWI) */
ast_mutex_init(&pri->lock);
sig_pri_sort_pri_chans(pri);
#if defined(HAVE_PRI_MWI)
/*
* Split the mwi_mailboxes configuration string into the mbox[]:
* mailbox_number[@context]{,mailbox_number[@context]}
*/
i = 0;
saveptr = pri->mwi_mailboxes;
while (i < ARRAY_LEN(pri->mbox)) {
mbox_number = strsep(&saveptr, ",");
if (!mbox_number) {
break;
}
/* Split the mailbox_number and context */
mbox_context = strchr(mbox_number, '@');
if (mbox_context) {
*mbox_context++ = '\0';
mbox_context = ast_strip(mbox_context);
}
mbox_number = ast_strip(mbox_number);
if (ast_strlen_zero(mbox_number)) {
/* There is no mailbox number. Skip it. */
continue;
}
if (ast_strlen_zero(mbox_context)) {
/* There was no context so use the default. */
mbox_context = "default";
}
/* Fill the mbox[] element. */
ast_str_set(&mwi_description, -1, "%s span %d[%d] MWI mailbox %s@%s",
sig_pri_cc_type_name, pri->span, i, mbox_number, mbox_context);
pri->mbox[i].sub = ast_event_subscribe(AST_EVENT_MWI, sig_pri_mwi_event_cb,
ast_str_buffer(mwi_description), pri,
AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mbox_number,
AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, mbox_context,
AST_EVENT_IE_END);
if (!pri->mbox[i].sub) {
ast_log(LOG_ERROR, "%s span %d could not subscribe to MWI events for %s@%s.",
sig_pri_cc_type_name, pri->span, mbox_number, mbox_context);
continue;
}
pri->mbox[i].number = mbox_number;
pri->mbox[i].context = mbox_context;
++i;
}
#endif /* defined(HAVE_PRI_MWI) */
for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
if (pri->fds[i] == -1) {
break;
}
switch (pri->sig) {
case SIG_BRI:
pri->dchans[i] = pri_new_bri(pri->fds[i], 1, pri->nodetype, pri->switchtype);
break;
case SIG_BRI_PTMP:
pri->dchans[i] = pri_new_bri(pri->fds[i], 0, pri->nodetype, pri->switchtype);
break;
default:
pri->dchans[i] = pri_new(pri->fds[i], pri->nodetype, pri->switchtype);
#if defined(HAVE_PRI_SERVICE_MESSAGES)
if (pri->enable_service_message_support) {
pri_set_service_message_support(pri->dchans[i], 1);
}
#endif /* defined(HAVE_PRI_SERVICE_MESSAGES) */
break;
}
pri_set_overlapdial(pri->dchans[i], (pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING) ? 1 : 0);
#ifdef HAVE_PRI_PROG_W_CAUSE
pri_set_chan_mapping_logical(pri->dchans[i], pri->qsigchannelmapping == DAHDI_CHAN_MAPPING_LOGICAL);
#endif
#ifdef HAVE_PRI_INBANDDISCONNECT
pri_set_inbanddisconnect(pri->dchans[i], pri->inbanddisconnect);
#endif
/* Enslave to master if appropriate */
if (i)
pri_enslave(pri->dchans[0], pri->dchans[i]);
if (!pri->dchans[i]) {
if (pri->fds[i] > 0)
close(pri->fds[i]);
pri->fds[i] = -1;
ast_log(LOG_ERROR, "Unable to create PRI structure\n");
return -1;
}
pri_set_debug(pri->dchans[i], SIG_PRI_DEBUG_DEFAULT);
pri_set_nsf(pri->dchans[i], pri->nsf);
#ifdef PRI_GETSET_TIMERS
for (x = 0; x < PRI_MAX_TIMERS; x++) {
if (pri->pritimers[x] != 0)
pri_set_timer(pri->dchans[i], x, pri->pritimers[x]);
}
#endif
}
/* Assume primary is the one we use */
pri->pri = pri->dchans[0];
#if defined(HAVE_PRI_CALL_HOLD)
pri_hold_enable(pri->pri, 1);
#endif /* defined(HAVE_PRI_CALL_HOLD) */
#if defined(HAVE_PRI_CALL_REROUTING)
pri_reroute_enable(pri->pri, 1);
#endif /* defined(HAVE_PRI_CALL_REROUTING) */
#if defined(HAVE_PRI_HANGUP_FIX)
pri_hangup_fix_enable(pri->pri, 1);
#endif /* defined(HAVE_PRI_HANGUP_FIX) */
#if defined(HAVE_PRI_CCSS)
pri_cc_enable(pri->pri, 1);
pri_cc_recall_mode(pri->pri, pri->cc_ptmp_recall_mode);
pri_cc_retain_signaling_req(pri->pri, pri->cc_qsig_signaling_link_req);
pri_cc_retain_signaling_rsp(pri->pri, pri->cc_qsig_signaling_link_rsp);
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_TRANSFER)
pri_transfer_enable(pri->pri, 1);
#endif /* defined(HAVE_PRI_TRANSFER) */
#if defined(HAVE_PRI_AOC_EVENTS)
pri_aoc_events_enable(pri->pri, 1);
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
#if defined(HAVE_PRI_CALL_WAITING)
pri_connect_ack_enable(pri->pri, 1);
#endif /* defined(HAVE_PRI_CALL_WAITING) */
#if defined(HAVE_PRI_MCID)
pri_mcid_enable(pri->pri, 1);
#endif /* defined(HAVE_PRI_MCID) */
pri->resetpos = -1;
if (ast_pthread_create_background(&pri->master, NULL, pri_dchannel, pri)) {
for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
if (!pri->dchans[i])
break;
if (pri->fds[i] > 0)
close(pri->fds[i]);
pri->fds[i] = -1;
}
ast_log(LOG_ERROR, "Unable to spawn D-channel: %s\n", strerror(errno));
return -1;
}
#if defined(HAVE_PRI_MWI)
/*
* Send the initial MWI indications from the event cache for this span.
*
* If we were loaded after app_voicemail the event would already be in
* the cache. If we were loaded before app_voicemail the event would not
* be in the cache yet and app_voicemail will send the event when it
* gets loaded.
*/
sig_pri_mwi_cache_update(pri);
#endif /* defined(HAVE_PRI_MWI) */
return 0;
}
| void sig_pri_stop_pri | ( | struct sig_pri_span * | pri | ) |
Stop PRI span.
| pri | Asterisk D channel control structure. |
Definition at line 6950 of file sig_pri.c.
References ARRAY_LEN, ast_event_unsubscribe(), sig_pri_span::mbox, and sig_pri_mbox::sub.
Referenced by __unload_module().
| static void sig_pri_transfer_rsp | ( | void * | data, |
| int | is_successful | ||
| ) | [static] |
Definition at line 1962 of file sig_pri.c.
References xfer_rsp_data::call, xfer_rsp_data::invoke_id, sig_pri_span::pri, and xfer_rsp_data::pri.
Referenced by sig_pri_handle_subcmds().
{
struct xfer_rsp_data *rsp = data;
pri_transfer_rsp(rsp->pri->pri, rsp->call, rsp->invoke_id, is_successful);
}
| void sig_pri_unload | ( | void | ) |
Unload the sig_pri submodule.
Definition at line 7961 of file sig_pri.c.
References ao2_ref.
Referenced by __unload_module().
{
#if defined(HAVE_PRI_CCSS)
if (sig_pri_cc_monitors) {
ao2_ref(sig_pri_cc_monitors, -1);
sig_pri_cc_monitors = NULL;
}
#endif /* defined(HAVE_PRI_CCSS) */
}
| static void sig_pri_unlock_private | ( | struct sig_pri_chan * | p | ) | [static] |
Definition at line 271 of file sig_pri.c.
References sig_pri_chan::calls, sig_pri_chan::chan_pvt, and sig_pri_callback::unlock_private.
Referenced by pri_dchannel(), pri_fixup_principle(), pri_send_callrerouting_facility_exec(), pri_send_keypad_facility_exec(), pri_ss_thread(), sig_pri_attempt_transfer(), sig_pri_handle_hold(), sig_pri_handle_retrieve(), and sig_pri_handle_subcmds().
{
if (p->calls->unlock_private)
p->calls->unlock_private(p->chan_pvt);
}
int pri_gendigittimeout = 8000 [static] |
Definition at line 88 of file sig_pri.c.
Referenced by pri_ss_thread().
int pri_matchdigittimeout = 3000 [static] |
Definition at line 86 of file sig_pri.c.
Referenced by pri_ss_thread().
struct ast_app_option sig_pri_call_opts[128] = { [ 'K' ] = { .flag = OPT_KEYPAD , .arg_index = OPT_ARG_KEYPAD + 1 }, [ 'R' ] = { .flag = OPT_REVERSE_CHARGE }, [ 'A' ] = { .flag = OPT_AOC_REQUEST , .arg_index = OPT_ARG_AOC_REQUEST + 1 }, } [static] |
Definition at line 6033 of file sig_pri.c.
Referenced by sig_pri_call().
struct ao2_container* sig_pri_cc_monitors [static] |
const char* sig_pri_cc_type_name [static] |
Upper level agent/monitor type name.
Definition at line 81 of file sig_pri.c.
Referenced by sig_pri_call(), sig_pri_cc_agent_req_ack(), sig_pri_cc_available(), sig_pri_cc_link_canceled(), sig_pri_find_cc_agent_by_cc_id(), sig_pri_handle_cis_subcmds(), sig_pri_handle_subcmds(), sig_pri_load(), and sig_pri_start_pri().