Asterisk - The Open Source Telephony Project GIT-master-6144b6b
Loading...
Searching...
No Matches
Data Structures | Macros | Functions | Variables
extension_state.c File Reference
#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/module.h"
#include "asterisk/extension_state.h"
#include "asterisk/pbx.h"
#include "asterisk/stasis.h"
#include "asterisk/stasis_message_router.h"
#include "asterisk/astobj2.h"
#include "asterisk/cli.h"
#include "pbx_private.h"
Include dependency graph for extension_state.c:

Go to the source code of this file.

Data Structures

struct  cfextension_states
 
struct  device_state_sources_vector
 
struct  extension_state
 Extension state information. More...
 
struct  extension_state_device_source
 Device state source feeding an extension state. More...
 

Macros

#define DEVICE_SOURCE_ELEM_VERSION_CMP(elem, value)   ((elem)->version != (value))
 device source non-matching version comparator for AST_VECTOR_REMOVE_CMP_UNORDERED()
 
#define EXTENSION_STATE_BUCKETS   563
 Number of buckets for extension states.
 
#define HINTDEVICE_DATA_LENGTH   16
 

Functions

static int action_extensionstatelist (struct mansession *s, const struct message *m)
 
enum ast_extension_states ast_devstate_to_extenstate (enum ast_device_state devstate)
 Map devstate to an extension state.
 
const char * ast_extension_state2str (int extension_state)
 Return string representation of the state of an extension.
 
struct ast_channelast_extension_state_get_device_causing_channel (const char *device, enum ast_device_state device_state)
 Get the channel that is causing the device to be in the given state, if any.
 
struct ast_extension_state_device_snapshotast_extension_state_get_latest_device_snapshot (struct ast_channel *chan, const char *exten, const char *context)
 Get the latest device state message for an extension.
 
struct ast_extension_state_presence_snapshotast_extension_state_get_latest_presence_snapshot (struct ast_channel *chan, const char *exten, const char *context)
 Get the latest presence state message for an extension.
 
int ast_extension_state_init (void)
 
struct stasis_topicast_extension_state_topic (const char *exten, const char *context)
 Get the Stasis topic to receive extension state messages for a specific extension.
 
struct stasis_topicast_extension_state_topic_all (void)
 Get the Stasis topic to receive all extension state messages.
 
 AST_THREADSTORAGE_CUSTOM_SCOPE (hintdevice_data, NULL, ast_free_ptr, static)
 
static char * complete_core_show_hint (const char *line, const char *word, int pos, int state)
 
static struct extension_stateextension_state_alloc (struct ast_exten *exten, struct ast_context *context)
 
static void extension_state_cleanup (void)
 
static int extension_state_cleanup_individual (void *obj, void *arg, int flags)
 
static void extension_state_destroy (void *obj)
 
static struct ast_extension_state_device_snapshotextension_state_device_snapshot_create (enum ast_extension_states device_state, struct device_state_sources_vector *device_state_sources, struct ast_extension_state_device_state_info *causing_device)
 
static void extension_state_device_snapshot_destroy (void *obj)
 
static struct extension_state_device_sourceextension_state_device_source_alloc (struct extension_state *state, const char *device)
 
static void extension_state_device_source_destroy (struct extension_state_device_source *source)
 
static void extension_state_device_state_cb (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static struct ast_extension_state_device_state_infoextension_state_device_state_info_alloc (const char *device, enum ast_device_state state)
 
static struct extension_stateextension_state_get (struct ast_channel *chan, const char *context, const char *extension)
 
static struct ast_extension_state_presence_snapshotextension_state_presence_snapshot_create (enum ast_presence_state presence_state, const char *presence_subtype, const char *presence_message)
 
static void extension_state_presence_snapshot_destroy (void *obj)
 
static void extension_state_presence_state_cb (void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
 
static struct stasis_messageextension_state_remove_message_create (const char *context, const char *extension)
 
static void extension_state_shutdown (struct extension_state *state)
 
static struct ast_extension_state_update_messageextension_state_update_message_create (const char *context, const char *extension, struct ast_extension_state_device_snapshot *old_device_snapshot, struct ast_extension_state_device_snapshot *new_device_snapshot, struct ast_extension_state_presence_snapshot *old_presence_snapshot, struct ast_extension_state_presence_snapshot *new_presence_snapshot)
 
static void extension_state_update_message_destroy (void *obj)
 
static int extension_state_update_sources (struct extension_state *state, struct ast_exten *exten)
 
static char * handle_show_hint (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_show_hints (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
void pbx_extension_state_hint_remove (struct ast_exten *exten, struct ast_context *context)
 
void pbx_extension_state_hint_set (struct ast_exten *exten, struct ast_context *context)
 
 STASIS_MESSAGE_TYPE_DEFN (ast_extension_state_remove_message_type)
 Stasis message type for extension state remove messages.
 
 STASIS_MESSAGE_TYPE_DEFN (ast_extension_state_update_message_type)
 Sort function for extension states.
 

Variables

static struct ast_cli_entry extension_state_cli []
 
static const struct cfextension_states extension_state_mappings []
 
static struct stasis_topicextension_state_topic_all
 Topic which receives all extension state updates.
 
static struct ao2_containerextension_states
 The global container of extension states.
 
static struct stasis_subscriptionpresence_state_sub
 Single presence state subscription, for all extension states.
 

Macro Definition Documentation

◆ DEVICE_SOURCE_ELEM_VERSION_CMP

#define DEVICE_SOURCE_ELEM_VERSION_CMP (   elem,
  value 
)    ((elem)->version != (value))

device source non-matching version comparator for AST_VECTOR_REMOVE_CMP_UNORDERED()

Parameters
elemElement to compare against
valueValue to compare with the vector element.
Returns
0 if element does not match.
Non-zero if element matches.

Definition at line 567 of file extension_state.c.

◆ EXTENSION_STATE_BUCKETS

#define EXTENSION_STATE_BUCKETS   563

Number of buckets for extension states.

Definition at line 125 of file extension_state.c.

◆ HINTDEVICE_DATA_LENGTH

#define HINTDEVICE_DATA_LENGTH   16

Definition at line 82 of file extension_state.c.

Function Documentation

◆ action_extensionstatelist()

static int action_extensionstatelist ( struct mansession s,
const struct message m 
)
static

Definition at line 1184 of file extension_state.c.

1185{
1186 const char *action_id = astman_get_header(m, "ActionID");
1187
1189 astman_send_error(s, m, "No dialplan hints are available");
1190 return 0;
1191 }
1192
1193 astman_send_listack(s, m, "Extension Statuses will follow", "start");
1194
1197 struct ao2_iterator it_states;
1198 struct extension_state *state;
1199 int count = 0;
1200
1201 it_states = ao2_iterator_init(extension_states, 0);
1202 for (; (state = ao2_iterator_next(&it_states)); ao2_ref(state, -1)) {
1203 if (state->extension[0] == '_') {
1204 continue;
1205 }
1206
1207 ++count;
1208
1209 astman_append(s, "Event: ExtensionStatus\r\n");
1210 if (!ast_strlen_zero(action_id)) {
1211 astman_append(s, "ActionID: %s\r\n", action_id);
1212 }
1213 ao2_lock(state);
1214 astman_append(s,
1215 "Exten: %s\r\n"
1216 "Context: %s\r\n"
1217 "Hint: %s\r\n"
1218 "Status: %d\r\n"
1219 "StatusText: %s\r\n\r\n",
1220 state->dialplan_extension,
1221 state->dialplan_context,
1222 state->hint_extension ? ast_get_extension_app(state->hint_extension) : "None",
1226 }
1227 ao2_iterator_destroy(&it_states);
1228 astman_send_list_complete_start(s, m, "ExtensionStateListComplete", count);
1230 } else {
1231 astman_send_error(s, m, "No dialplan hints are available");
1232 }
1233
1235
1236 return 0;
1237}
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_lock(a)
Definition astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
const char * ast_extension_state2str(int extension_state)
Return string representation of the state of an extension.
static struct ao2_container * extension_states
The global container of extension states.
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition manager.c:2042
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition manager.c:2000
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition manager.c:2078
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1661
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition manager.c:2086
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1921
const char * ast_get_extension_app(struct ast_exten *e)
Definition pbx.c:6715
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
Extension state information.
struct ast_extension_state_device_snapshot * device_snapshot
The current device snapshot for the extension.

References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_extension_state2str(), ast_get_extension_app(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_error(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), and extension_states.

Referenced by ast_extension_state_init().

◆ ast_devstate_to_extenstate()

enum ast_extension_states ast_devstate_to_extenstate ( enum ast_device_state  devstate)

Map devstate to an extension state.

Parameters
[in]devstatedevice state
Returns
the extension state mapping.

Definition at line 1136 of file extension_state.c.

1137{
1138 switch (devstate) {
1139 case AST_DEVICE_ONHOLD:
1140 return AST_EXTENSION_ONHOLD;
1141 case AST_DEVICE_BUSY:
1142 return AST_EXTENSION_BUSY;
1143 case AST_DEVICE_UNKNOWN:
1146 case AST_DEVICE_INVALID:
1150 case AST_DEVICE_RINGING:
1151 return AST_EXTENSION_RINGING;
1152 case AST_DEVICE_INUSE:
1153 return AST_EXTENSION_INUSE;
1156 case AST_DEVICE_TOTAL: /* not a device state, included for completeness */
1157 break;
1158 }
1159
1161}
@ AST_DEVICE_RINGINUSE
Definition devicestate.h:60
@ AST_DEVICE_INUSE
Definition devicestate.h:55
@ AST_DEVICE_UNKNOWN
Definition devicestate.h:53
@ AST_DEVICE_ONHOLD
Definition devicestate.h:61
@ AST_DEVICE_RINGING
Definition devicestate.h:59
@ AST_DEVICE_INVALID
Definition devicestate.h:57
@ AST_DEVICE_BUSY
Definition devicestate.h:56
@ AST_DEVICE_NOT_INUSE
Definition devicestate.h:54
@ AST_DEVICE_TOTAL
Definition devicestate.h:62
@ AST_DEVICE_UNAVAILABLE
Definition devicestate.h:58
@ AST_EXTENSION_RINGING
Definition pbx.h:68
@ AST_EXTENSION_NOT_INUSE
Definition pbx.h:64
@ AST_EXTENSION_INUSE
Definition pbx.h:65
@ AST_EXTENSION_UNAVAILABLE
Definition pbx.h:67
@ AST_EXTENSION_ONHOLD
Definition pbx.h:69
@ AST_EXTENSION_BUSY
Definition pbx.h:66

References AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_RINGINUSE, AST_DEVICE_TOTAL, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, AST_EXTENSION_BUSY, AST_EXTENSION_INUSE, AST_EXTENSION_NOT_INUSE, AST_EXTENSION_ONHOLD, AST_EXTENSION_RINGING, and AST_EXTENSION_UNAVAILABLE.

Referenced by AST_TEST_DEFINE(), extension_state_device_state_cb(), and extension_state_update_sources().

◆ ast_extension_state2str()

const char * ast_extension_state2str ( int  extension_state)

Return string representation of the state of an extension.

Parameters
extension_stateis the numerical state delivered by ast_extension_state
Returns
the state of an extension as string

Definition at line 1163 of file extension_state.c.

1164{
1165 int i;
1166
1167 for (i = 0; (i < ARRAY_LEN(extension_state_mappings)); i++) {
1170 }
1171 return "Unknown";
1172}
static const struct cfextension_states extension_state_mappings[]
const char *const text
#define ARRAY_LEN(a)
Definition utils.h:706

References ARRAY_LEN, extension_state_mappings, and cfextension_states::text.

Referenced by action_extensionstate(), action_extensionstatelist(), AST_TEST_DEFINE(), exten_state_publisher_state_cb(), handle_show_hint(), handle_show_hints(), manager_state_cb(), and to_ami().

◆ ast_extension_state_get_device_causing_channel()

struct ast_channel * ast_extension_state_get_device_causing_channel ( const char *  device,
enum ast_device_state  device_state 
)

Get the channel that is causing the device to be in the given state, if any.

Since
23.5.0
22.11.0
20.21.0
Parameters
deviceThe device itself
device_stateThe state of the device
Returns
The channel that is causing the device to be in the given state
Return values
NULLif there is no channel causing the device to be in the given state

Definition at line 1070 of file extension_state.c.

1071{
1072 enum ast_channel_state search_state = 0; /* prevent false uninit warning */
1073 char match[AST_CHANNEL_NAME];
1074 struct ast_channel_iterator *chan_iter;
1075 struct ast_channel *chan, *channel = NULL;
1076 struct timeval chantime = {0, }; /* prevent false uninit warning */
1077
1078 switch (device_state) {
1079 case AST_DEVICE_RINGING:
1081 /* find ringing channel */
1082 search_state = AST_STATE_RINGING;
1083 break;
1084 case AST_DEVICE_BUSY:
1085 /* find busy channel */
1086 search_state = AST_STATE_BUSY;
1087 break;
1088 case AST_DEVICE_ONHOLD:
1089 case AST_DEVICE_INUSE:
1090 /* find up channel */
1091 search_state = AST_STATE_UP;
1092 break;
1093 case AST_DEVICE_UNKNOWN:
1095 case AST_DEVICE_INVALID:
1097 case AST_DEVICE_TOTAL /* not a state */:
1098 /* no channels are of interest */
1099 return NULL;
1100 }
1101
1102 /* iterate over all channels of the device */
1103 snprintf(match, sizeof(match), "%s-", device);
1104 chan_iter = ast_channel_iterator_by_name_new(match, strlen(match));
1105 for (; (chan = ast_channel_iterator_next(chan_iter)); ast_channel_unref(chan)) {
1106 ast_channel_lock(chan);
1107 /* this channel's state doesn't match */
1108 if (search_state != ast_channel_state(chan)) {
1109 ast_channel_unlock(chan);
1110 continue;
1111 }
1112 /* any non-ringing channel will fit */
1113 if (search_state != AST_STATE_RINGING) {
1114 ast_channel_unlock(chan);
1115 channel = chan;
1116 break;
1117 }
1118 /* but we need the oldest ringing channel of the device to match with undirected pickup */
1119 if (!channel) {
1120 chantime = ast_channel_creationtime(chan);
1121 ast_channel_ref(chan); /* must ref it! */
1122 channel = chan;
1123 } else if (ast_tvcmp(ast_channel_creationtime(chan), chantime) < 0) {
1124 chantime = ast_channel_creationtime(chan);
1125 ast_channel_unref(channel);
1126 ast_channel_ref(chan); /* must ref it! */
1127 channel = chan;
1128 }
1129 ast_channel_unlock(chan);
1130 }
1132
1133 return channel;
1134}
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition chan_iax2.c:2401
struct ast_channel_iterator * ast_channel_iterator_by_name_new(const char *name, size_t name_len)
Create a new channel iterator based on name.
Definition channel.c:1368
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition channel.c:1349
#define ast_channel_lock(chan)
Definition channel.h:2983
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition channel.c:1388
#define ast_channel_ref(c)
Increase channel reference count.
Definition channel.h:3008
struct timeval ast_channel_creationtime(struct ast_channel *chan)
#define AST_CHANNEL_NAME
Definition channel.h:173
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3019
#define ast_channel_unlock(chan)
Definition channel.h:2984
ast_channel_state
ast_channel states
@ AST_STATE_RINGING
@ AST_STATE_BUSY
@ AST_STATE_UP
#define NULL
Definition resample.c:96
Main Channel structure associated with a channel.
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller,...
Definition time.h:137

References ast_channel_creationtime(), ast_channel_iterator_by_name_new(), ast_channel_iterator_destroy(), ast_channel_iterator_next(), ast_channel_lock, AST_CHANNEL_NAME, ast_channel_ref, ast_channel_unlock, ast_channel_unref, AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_RINGINUSE, AST_DEVICE_TOTAL, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, AST_STATE_BUSY, AST_STATE_RINGING, AST_STATE_UP, ast_tvcmp(), match(), and NULL.

Referenced by extension_state_legacy_create_device_state_info().

◆ ast_extension_state_get_latest_device_snapshot()

struct ast_extension_state_device_snapshot * ast_extension_state_get_latest_device_snapshot ( struct ast_channel chan,
const char *  exten,
const char *  context 
)

Get the latest device state message for an extension.

Since
23.5.0
22.11.0
20.21.0
Parameters
chanThe optional channel to get the underlying hint from, if it needs to be created
extenThe extension to get the device state message for
contextThe context of the extension
Returns
The latest device snapshot for the extension
Return values
NULLif the extension does not have a configured hint

Definition at line 1317 of file extension_state.c.

1319{
1320 struct extension_state *state;
1321 struct ast_extension_state_device_snapshot *device_snapshot;
1322
1323 state = extension_state_get(chan, context, exten);
1324 if (!state) {
1325 return NULL;
1326 }
1327
1328 ao2_lock(state);
1329 device_snapshot = ao2_bump(state->device_snapshot);
1331 ao2_ref(state, -1);
1332
1333 return device_snapshot;
1334}
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
static struct extension_state * extension_state_get(struct ast_channel *chan, const char *context, const char *extension)
Device snapshot for an extension state.

References ao2_bump, ao2_lock, ao2_ref, ao2_unlock, extension_state_get(), and NULL.

Referenced by ast_extension_state(), and ast_extension_state_extended().

◆ ast_extension_state_get_latest_presence_snapshot()

struct ast_extension_state_presence_snapshot * ast_extension_state_get_latest_presence_snapshot ( struct ast_channel chan,
const char *  exten,
const char *  context 
)

Get the latest presence state message for an extension.

Since
23.5.0
22.11.0
20.21.0
Parameters
chanThe optional channel to get the underlying hint from, if it needs to be created
extenThe extension to get the presence state message for
contextThe context of the extension
Returns
The latest presence snapshot for the extension
Return values
NULLif the extension does not have a configured hint

Definition at line 1336 of file extension_state.c.

1338{
1339 struct extension_state *state;
1340 struct ast_extension_state_presence_snapshot *presence_snapshot;
1341
1342 state = extension_state_get(chan, context, exten);
1343 if (!state) {
1344 return NULL;
1345 }
1346
1347 ao2_lock(state);
1348 presence_snapshot = ao2_bump(state->presence_snapshot);
1350 ao2_ref(state, -1);
1351
1352 return presence_snapshot;
1353}
Presence snapshot for an extension state.

References ao2_bump, ao2_lock, ao2_ref, ao2_unlock, extension_state_get(), and NULL.

Referenced by ast_hint_presence_state().

◆ ast_extension_state_init()

int ast_extension_state_init ( void  )

Provided by extension_state.c

Definition at line 1560 of file extension_state.c.

1561{
1563 return -1;
1564 }
1565
1567 return -1;
1568 }
1569
1570 /* Initialize extension state subsystem */
1572 extension_state_sort_fn, extension_state_cmp_fn);
1573 if (!extension_states) {
1574 ast_log(LOG_ERROR, "Failed to allocate new states container\n");
1575 return -1;
1576 }
1577
1578 extension_state_topic_all = stasis_topic_create("extension_state:all");
1580 ast_log(LOG_ERROR, "Failed to create extension state topic\n");
1581 return -1;
1582 }
1583
1585 if (!presence_state_sub) {
1586 ast_log(LOG_ERROR, "Failed to create subscription to receive presence state updates\n");
1587 return -1;
1588 }
1591
1595
1596 return 0;
1597}
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition clicompat.c:19
#define ast_log
Definition astobj2.c:42
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition astobj2.h:363
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition astobj2.h:1349
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
static struct stasis_topic * extension_state_topic_all
Topic which receives all extension state updates.
static struct ast_cli_entry extension_state_cli[]
static int action_extensionstatelist(struct mansession *s, const struct message *m)
static struct stasis_subscription * presence_state_sub
Single presence state subscription, for all extension states.
static void extension_state_presence_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
static void extension_state_cleanup(void)
struct stasis_message_type * ast_extension_state_update_message_type(void)
Get extension state update message type.
struct stasis_message_type * ast_extension_state_remove_message_type(void)
Get extension state remove message type.
#define LOG_ERROR
#define EVENT_FLAG_REPORTING
Definition manager.h:84
#define ast_manager_register_xml_core(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition manager.h:204
#define EVENT_FLAG_CALL
Definition manager.h:76
struct stasis_topic * ast_presence_state_topic_all(void)
Get presence state topic.
struct stasis_message_type * ast_presence_state_message_type(void)
Get presence state message type.
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
Definition stasis.h:297
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
Definition stasis.c:684
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition stasis.c:1101
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition stasis.c:1155
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition stasis.h:1524
#define stasis_subscribe(topic, callback, data)
Definition stasis.h:649

References action_extensionstatelist(), AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_rbtree, ARRAY_LEN, ast_cli_register_multiple, ast_extension_state_remove_message_type(), ast_extension_state_update_message_type(), ast_log, ast_manager_register_xml_core, ast_presence_state_message_type(), ast_presence_state_topic_all(), ast_register_cleanup(), EVENT_FLAG_CALL, EVENT_FLAG_REPORTING, extension_state_cleanup(), extension_state_cli, extension_state_presence_state_cb(), extension_state_topic_all, extension_states, LOG_ERROR, NULL, presence_state_sub, STASIS_MESSAGE_TYPE_INIT, stasis_subscribe, stasis_subscription_accept_message_type(), STASIS_SUBSCRIPTION_FILTER_SELECTIVE, stasis_subscription_set_filter(), and stasis_topic_create().

Referenced by asterisk_daemon().

◆ ast_extension_state_topic()

struct stasis_topic * ast_extension_state_topic ( const char *  exten,
const char *  context 
)

Get the Stasis topic to receive extension state messages for a specific extension.

Since
23.5.0
22.11.0
20.21.0
Parameters
extenThe extension to receive extension state messages for
contextThe context of the extension
Returns
The topic for extension state messages
Return values
NULLif it has not been allocated

Definition at line 1299 of file extension_state.c.

1300{
1301 struct extension_state *state;
1302 struct stasis_topic *topic;
1303
1304 state = extension_state_get(NULL, context, exten);
1305 if (!state) {
1306 return NULL;
1307 }
1308
1309 ao2_lock(state);
1310 topic = ao2_bump(state->extension_state_topic);
1312 ao2_ref(state, -1);
1313
1314 return topic;
1315}

References ao2_bump, ao2_lock, ao2_ref, ao2_unlock, extension_state_get(), and NULL.

Referenced by extension_state_legacy_add_destroy().

◆ ast_extension_state_topic_all()

struct stasis_topic * ast_extension_state_topic_all ( void  )

Get the Stasis topic to receive all extension state messages.

Since
23.5.0
22.11.0
20.21.0
Returns
The topic for extension state messages
Return values
NULLif it has not been allocated

Definition at line 1294 of file extension_state.c.

1295{
1297}

References extension_state_topic_all.

Referenced by extension_state_legacy_add_destroy().

◆ AST_THREADSTORAGE_CUSTOM_SCOPE()

AST_THREADSTORAGE_CUSTOM_SCOPE ( hintdevice_data  ,
NULL  ,
ast_free_ptr  ,
static   
)

◆ complete_core_show_hint()

static char * complete_core_show_hint ( const char *  line,
const char *  word,
int  pos,
int  state 
)
static

Definition at line 1426 of file extension_state.c.

1427{
1428 struct extension_state *extstate;
1429 char *ret = NULL;
1430 int which = 0;
1431 int wordlen;
1432 struct ao2_iterator i;
1433
1434 if (pos != 3)
1435 return NULL;
1436
1437 wordlen = strlen(word);
1438
1439 /* walk through all hints */
1441 for (; (extstate = ao2_iterator_next(&i)); ao2_ref(extstate, -1)) {
1442 ao2_lock(extstate);
1443 if (!strncasecmp(word, extstate->dialplan_extension, wordlen) && ++which > state) {
1444 ret = ast_strdup(extstate->dialplan_extension);
1445 ao2_unlock(extstate);
1446 ao2_ref(extstate, -1);
1447 break;
1448 }
1449 ao2_unlock(extstate);
1450 }
1452
1453 return ret;
1454}
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
short word
char dialplan_extension[AST_MAX_EXTENSION]
The dialplan extension.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_strdup, extension_state::dialplan_extension, extension_states, and NULL.

Referenced by handle_show_hint().

◆ extension_state_alloc()

static struct extension_state * extension_state_alloc ( struct ast_exten exten,
struct ast_context context 
)
static

Definition at line 925 of file extension_state.c.

926{
928 struct extension_state *state;
929 char *extension_state_topic_name;
930
931 snprintf(extension, sizeof(extension), "%s@%s", ast_get_extension_name(exten), ast_get_context_name(context));
932
933 /*
934 * Each individual extension state has its own lock to ensure that when updating it
935 * we do not cause problems for either the existing topic ingesting updates
936 * or any access to the extension state cached message.
937 */
938 state = ao2_alloc(sizeof(*state) + strlen(extension) + 1, extension_state_destroy);
939 if (!state) {
940 return NULL;
941 }
942
943 ast_copy_string(state->dialplan_context, ast_get_context_name(context), sizeof(state->dialplan_context));
944 ast_copy_string(state->dialplan_extension, ast_get_extension_name(exten), sizeof(state->dialplan_extension));
945 strcpy(state->extension, extension); /* Safe */
946 AST_VECTOR_INIT(&state->device_state_sources, 0);
947
948 /* These are the default if no sources are present */
950 &state->device_state_sources, NULL);
952 if (!state->device_snapshot || !state->presence_snapshot) {
953 ao2_ref(state, -1);
954 return NULL;
955 }
956
957 /*
958 * We don't actually access the contents of exten past guarantee of it being valid so we can safely
959 * store a pointer to just do pointer comparison.
960 */
961 state->hint_extension = exten;
962
963 /* Pattern match extensions don't have sources or a topic, so return early */
964 if (extension[0] == '_') {
965 return state;
966 }
967
968 /* We most likely have at least one device state source */
969 if (AST_VECTOR_INIT(&state->device_state_sources, 1)) {
970 ao2_ref(state, -1);
971 return NULL;
972 }
973
974 if (ast_asprintf(&extension_state_topic_name, "extension_state:extension/%s", extension) < 0) {
975 ao2_ref(state, -1);
976 return NULL;
977 }
978
979 state->extension_state_topic = stasis_topic_create(extension_state_topic_name);
980 ast_free(extension_state_topic_name);
981 if (!state->extension_state_topic) {
982 ao2_ref(state, -1);
983 return NULL;
984 }
985
986 state->extension_state_forwarder = stasis_forward_all(state->extension_state_topic, extension_state_topic_all);
987 if (!state->extension_state_forwarder) {
988 ao2_ref(state, -1);
989 return NULL;
990 }
991
992 return state;
993}
#define ast_free(a)
Definition astmm.h:180
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition astmm.h:267
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
#define AST_MAX_CONTEXT
Definition channel.h:135
#define AST_MAX_EXTENSION
Definition channel.h:134
static void extension_state_destroy(void *obj)
static struct ast_extension_state_presence_snapshot * extension_state_presence_snapshot_create(enum ast_presence_state presence_state, const char *presence_subtype, const char *presence_message)
static struct ast_extension_state_device_snapshot * extension_state_device_snapshot_create(enum ast_extension_states device_state, struct device_state_sources_vector *device_state_sources, struct ast_extension_state_device_state_info *causing_device)
const char * ast_get_context_name(struct ast_context *con)
Definition ael_main.c:421
const char * ast_get_extension_name(struct ast_exten *exten)
Definition pbx.c:6667
@ AST_PRESENCE_NOT_SET
struct stasis_forward * stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic)
Create a subscription which forwards all messages from one topic to another.
Definition stasis.c:1656
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
structure to hold extensions
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124

References ao2_alloc, ao2_ref, ast_asprintf, ast_copy_string(), AST_EXTENSION_UNAVAILABLE, ast_free, ast_get_context_name(), ast_get_extension_name(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, AST_PRESENCE_NOT_SET, AST_VECTOR_INIT, extension_state_destroy(), extension_state_device_snapshot_create(), extension_state_presence_snapshot_create(), extension_state_topic_all, NULL, stasis_forward_all(), and stasis_topic_create().

Referenced by pbx_extension_state_hint_set().

◆ extension_state_cleanup()

static void extension_state_cleanup ( void  )
static

Definition at line 1547 of file extension_state.c.

1548{
1550 ast_manager_unregister("ExtensionStateList");
1551 if (extension_states) {
1554 }
1558}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
@ OBJ_NODATA
Definition astobj2.h:1044
@ OBJ_MULTIPLE
Definition astobj2.h:1049
@ OBJ_UNLINK
Definition astobj2.h:1039
static int extension_state_cleanup_individual(void *obj, void *arg, int flags)
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7716
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition stasis.h:1546
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition stasis.c:1212

References ao2_callback, ao2_ref, ARRAY_LEN, ast_cli_unregister_multiple(), ast_extension_state_remove_message_type(), ast_extension_state_update_message_type(), ast_manager_unregister(), extension_state_cleanup_individual(), extension_state_cli, extension_states, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, presence_state_sub, STASIS_MESSAGE_TYPE_CLEANUP, and stasis_unsubscribe_and_join().

Referenced by ast_extension_state_init().

◆ extension_state_cleanup_individual()

static int extension_state_cleanup_individual ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 1534 of file extension_state.c.

1535{
1536 struct extension_state *state = obj;
1537
1539
1540 return CMP_MATCH;
1541}
@ CMP_MATCH
Definition astobj2.h:1027
static void extension_state_shutdown(struct extension_state *state)

References CMP_MATCH, and extension_state_shutdown().

Referenced by extension_state_cleanup().

◆ extension_state_destroy()

static void extension_state_destroy ( void *  obj)
static

Definition at line 727 of file extension_state.c.

728{
729 struct extension_state *state = obj;
730
731 ao2_cleanup(state->device_snapshot);
732 ao2_cleanup(state->presence_snapshot);
733 ao2_cleanup(state->extension_state_topic);
734
735 ast_free(state->presence_sources_string);
736}
#define ao2_cleanup(obj)
Definition astobj2.h:1934

References ao2_cleanup, and ast_free.

Referenced by extension_state_alloc().

◆ extension_state_device_snapshot_create()

static struct ast_extension_state_device_snapshot * extension_state_device_snapshot_create ( enum ast_extension_states  device_state,
struct device_state_sources_vector device_state_sources,
struct ast_extension_state_device_state_info causing_device 
)
static

Definition at line 290 of file extension_state.c.

293{
294 struct ast_extension_state_device_snapshot *device_snapshot;
295 int i;
296
297 device_snapshot = ao2_alloc_options(sizeof(*device_snapshot),
299 if (!device_snapshot) {
300 return NULL;
301 }
302
303 device_snapshot->state = device_state;
304 device_snapshot->causing_device = ao2_bump(causing_device);
305 if (AST_VECTOR_INIT(&device_snapshot->additional_devices, AST_VECTOR_SIZE(device_state_sources))) {
306 ao2_ref(device_snapshot, -1);
307 return NULL;
308 }
309
310 for (i = 0; i < AST_VECTOR_SIZE(device_state_sources); i++) {
311 struct extension_state_device_source *source = AST_VECTOR_GET(device_state_sources, i);
312
313 if (causing_device && source->info == causing_device) {
314 continue;
315 }
316
317 AST_VECTOR_APPEND(&device_snapshot->additional_devices, ao2_bump(source->info));
318 }
319
320 return device_snapshot;
321}
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition astobj2.h:367
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition astobj2.h:404
static void extension_state_device_snapshot_destroy(void *obj)
struct ast_extension_state_device_snapshot::@232 additional_devices
Vector of additional device states that contributed to update.
struct ast_extension_state_device_state_info * causing_device
The device that caused this update.
enum ast_extension_states state
The state of the extension.
Device state source feeding an extension state.
struct ast_extension_state_device_state_info * info
The current state of the device - this is immutable.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:620
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:691

References ast_extension_state_device_snapshot::additional_devices, AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_bump, ao2_ref, AST_VECTOR_APPEND, AST_VECTOR_GET, AST_VECTOR_INIT, AST_VECTOR_SIZE, ast_extension_state_device_snapshot::causing_device, extension_state_device_snapshot_destroy(), extension_state_device_source::info, NULL, and ast_extension_state_device_snapshot::state.

Referenced by extension_state_alloc(), extension_state_device_state_cb(), and extension_state_update_sources().

◆ extension_state_device_snapshot_destroy()

static void extension_state_device_snapshot_destroy ( void *  obj)
static

Definition at line 269 of file extension_state.c.

270{
271 struct ast_extension_state_device_snapshot *device_snapshot = obj;
272
273 ao2_cleanup(device_snapshot->causing_device);
275 AST_VECTOR_FREE(&device_snapshot->additional_devices);
276}
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition vector.h:185
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition vector.h:873

References ast_extension_state_device_snapshot::additional_devices, ao2_cleanup, AST_VECTOR_CALLBACK_VOID, AST_VECTOR_FREE, and ast_extension_state_device_snapshot::causing_device.

Referenced by extension_state_device_snapshot_create().

◆ extension_state_device_source_alloc()

static struct extension_state_device_source * extension_state_device_source_alloc ( struct extension_state state,
const char *  device 
)
static

Definition at line 452 of file extension_state.c.

453{
454 struct extension_state_device_source *source;
455 struct stasis_topic *topic;
456
457 /*
458 * Ensure that we have a direct device state topic for the device, note this is returned without a reference but
459 * is guaranteed to exist regardless.
460 */
461 topic = ast_device_state_topic(device);
462 if (!topic) {
463 return NULL;
464 }
465
466 /*
467 * The device state source is only used within the extension state and is never
468 * passed around so the overhead of an ao2 object with reference counting is unnecessary.
469 */
470 source = ast_calloc(1, sizeof(*source));
471 if (!source) {
472 return NULL;
473 }
474
476 if (!source->info) {
478 return NULL;
479 }
480
481 /*
482 * We do a synchronous subscription to the device state topic, as our callback is extremely
483 * short lived and the added overhead of queueing to a taskprocessor for another thread to handle
484 * it is just not worth it.
485 */
487 if (!source->device_state_subscription) {
489 return NULL;
490 }
491
494
495 return source;
496}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
struct stasis_topic * ast_device_state_topic(const char *device)
Get the Stasis topic for device state messages for a specific device.
ast_device_state
Device States.
Definition devicestate.h:52
static void extension_state_device_source_destroy(struct extension_state_device_source *source)
static void extension_state_device_state_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
static struct ast_extension_state_device_state_info * extension_state_device_state_info_alloc(const char *device, enum ast_device_state state)
#define stasis_subscribe_synchronous(topic, callback, data)
Definition stasis.h:711
struct stasis_subscription * device_state_subscription
Synchronous subscription to the device state topic.

References ast_calloc, ast_device_state_message_type(), ast_device_state_topic(), extension_state_device_source::device_state_subscription, extension_state_device_source_destroy(), extension_state_device_state_cb(), extension_state_device_state_info_alloc(), extension_state_device_source::info, NULL, stasis_subscribe_synchronous, stasis_subscription_accept_message_type(), STASIS_SUBSCRIPTION_FILTER_SELECTIVE, and stasis_subscription_set_filter().

Referenced by extension_state_update_sources().

◆ extension_state_device_source_destroy()

static void extension_state_device_source_destroy ( struct extension_state_device_source source)
static

Definition at line 225 of file extension_state.c.

226{
227 if (source->device_state_subscription) {
229 }
230 ao2_cleanup(source->info);
231 ast_free(source);
232}
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition stasis.c:1049

References ao2_cleanup, ast_free, extension_state_device_source::device_state_subscription, extension_state_device_source::info, and stasis_unsubscribe().

Referenced by extension_state_device_source_alloc(), extension_state_shutdown(), and extension_state_update_sources().

◆ extension_state_device_state_cb()

static void extension_state_device_state_cb ( void *  userdata,
struct stasis_subscription sub,
struct stasis_message msg 
)
static

Definition at line 334 of file extension_state.c.

336{
337 struct extension_state *state = userdata;
338 struct ast_device_state_message *device_state;
339 struct ast_devstate_aggregate agg;
340 struct ast_extension_state_device_state_info *extension_device_state_info;
341 int i;
342 unsigned int updated = 0;
343 enum ast_extension_states new_device_state;
344
346 return;
347 }
348
349 device_state = stasis_message_data(msg);
350
351 /* We only care about the aggregate state */
352 if (device_state->eid) {
353 return;
354 }
355
357
358 /*
359 * Alrighty, the reason that we store an extension_device_state_info is to reduce the memory allocation that
360 * has to occur every time we get a device state update and have to construct a new message. If the extension
361 * state contains only a single device source we have to do this anyway, but if there's multiple then if we
362 * didn't store the result we'd be creating new ones every message to put in the additional_devices vector.
363 */
364 extension_device_state_info = extension_state_device_state_info_alloc(device_state->device, device_state->state);
365 if (!extension_device_state_info) {
366 return;
367 }
368
370
371 for (i = 0; i < AST_VECTOR_SIZE(&state->device_state_sources); i++) {
372 struct extension_state_device_source *source = AST_VECTOR_GET(&state->device_state_sources, i);
373
374 if (!strcmp(source->info->device, device_state->device)) {
375 ao2_replace(source->info, extension_device_state_info);
376 updated = 1;
377 }
378
379 ast_devstate_aggregate_add(&agg, source->info->state);
380 }
381
382 /* We don't really care about the device state info contents now, so we can drop the reference */
383 ao2_ref(extension_device_state_info, -1);
384
385 /*
386 * It's possible for a device state update to come in for a device which is no longer feeding this
387 * extension state if it has been updated, so only actually care about the new device state if a
388 * source has actually been updated.
389 */
390 if (!updated) {
392 return;
393 }
394
395 /*
396 * We actually update things and raise a message if the state is different, or if the state is ringing
397 * as that can actually just be an update that someone else is ringing the same extension.
398 */
400 if ((state->device_snapshot->state != new_device_state) || (new_device_state & AST_EXTENSION_RINGING)) {
401 struct ast_extension_state_device_snapshot *device_snapshot;
402 struct ast_extension_state_update_message *update_message;
403 struct stasis_message *message;
404
405 /* Now above you probably noticed I dropped the reference for extension_device_state_info but now I'm
406 * passing it in here. Don't panic - a reference exists on the device state source still and since we
407 * have the state locked it can't go away.
408 */
409 device_snapshot = extension_state_device_snapshot_create(new_device_state, &state->device_state_sources,
410 extension_device_state_info);
411 if (!device_snapshot) {
413 return;
414 }
415
416 update_message = extension_state_update_message_create(state->dialplan_context, state->dialplan_extension,
417 state->device_snapshot, device_snapshot, state->presence_snapshot, state->presence_snapshot);
418
419 /* Even if we can't publish an update message we still ensure the local cached snapshot is up to date */
420 ao2_replace(state->device_snapshot, device_snapshot);
421 ao2_ref(device_snapshot, -1);
422
423 if (!update_message) {
425 return;
426 }
427
428 /* Inform any subscribers of the change to the device snapshot */
430 if (message) {
431 stasis_publish(state->extension_state_topic, message);
432 ao2_ref(message, -1);
433 }
434
435 ao2_ref(update_message, -1);
436 }
437
439}
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Definition astobj2.h:501
void ast_devstate_aggregate_add(struct ast_devstate_aggregate *agg, enum ast_device_state state)
Add a device state to the aggregate device state.
void ast_devstate_aggregate_init(struct ast_devstate_aggregate *agg)
Initialize aggregate device state.
enum ast_device_state ast_devstate_aggregate_result(struct ast_devstate_aggregate *agg)
Get the aggregate device state result.
enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate)
Map devstate to an extension state.
static struct ast_extension_state_update_message * extension_state_update_message_create(const char *context, const char *extension, struct ast_extension_state_device_snapshot *old_device_snapshot, struct ast_extension_state_device_snapshot *new_device_snapshot, struct ast_extension_state_presence_snapshot *old_presence_snapshot, struct ast_extension_state_presence_snapshot *new_presence_snapshot)
ast_extension_states
Extension states.
Definition pbx.h:61
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition stasis.c:1589
The structure that contains device state.
enum ast_device_state state
const struct ast_eid * eid
The EID of the server where this message originated.
You shouldn't care about the contents of this struct.
Individual device states that contributed to snapshot.
enum ast_device_state state
The state of the device.
char device[0]
The name of the device.
Stasis message for extension state update message.

References ao2_lock, ao2_ref, ao2_replace, ao2_unlock, ast_device_state_message_type(), ast_devstate_aggregate_add(), ast_devstate_aggregate_init(), ast_devstate_aggregate_result(), ast_devstate_to_extenstate(), AST_EXTENSION_RINGING, ast_extension_state_update_message_type(), AST_VECTOR_GET, AST_VECTOR_SIZE, ast_device_state_message::device, ast_extension_state_device_state_info::device, ast_device_state_message::eid, extension_state_device_snapshot_create(), extension_state_device_state_info_alloc(), extension_state_update_message_create(), extension_state_device_source::info, stasis_message_create(), stasis_message_data(), stasis_publish(), ast_device_state_message::state, and ast_extension_state_device_state_info::state.

Referenced by extension_state_device_source_alloc().

◆ extension_state_device_state_info_alloc()

static struct ast_extension_state_device_state_info * extension_state_device_state_info_alloc ( const char *  device,
enum ast_device_state  state 
)
static

Definition at line 244 of file extension_state.c.

246{
248
249 info = ao2_alloc_options(sizeof(*info) + strlen(device) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
250 if (!info) {
251 return NULL;
252 }
253
254 info->state = state;
255 strcpy(info->device, device); /* Safe */
256
257 return info;
258}

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ast_extension_state_device_state_info::device, NULL, and ast_extension_state_device_state_info::state.

Referenced by extension_state_device_source_alloc(), and extension_state_device_state_cb().

◆ extension_state_get()

static struct extension_state * extension_state_get ( struct ast_channel chan,
const char *  context,
const char *  extension 
)
static

Definition at line 1007 of file extension_state.c.

1008{
1009 struct extension_state *state;
1010 struct ast_exten *hint_exten;
1011 struct pbx_find_info q = { .stacklen = 0 };
1012 char location[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2];
1013
1014 /* We optimistically search for the extension state using the provided context and extension */
1015 snprintf(location, sizeof(location), "%s@%s", extension, context);
1017 if (state) {
1018 return state;
1019 }
1020
1021 /*
1022 * Pattern match extensions do exist within extension state for the purposes of listing them out,
1023 * but they can't resolve down to anything else
1024 */
1025 if (extension[0] == '_') {
1026 return NULL;
1027 }
1028
1030
1031 /*
1032 * We can't use the provided context and extension as-is because an include
1033 * could have resulted in the context being different than what was provided.
1034 * To handle this we query the dialplan to find where the hint actually is.
1035 * We also need to do this to determine if this is a pattern match or an explicit
1036 * extension.
1037 */
1038 hint_exten = pbx_find_extension(chan, NULL, &q, context, extension,
1039 PRIORITY_HINT, NULL, "", E_MATCH);
1040 if (!hint_exten) {
1041 /*
1042 * The extension must ALWAYS exist in the dialplan in some capacity. It is
1043 * either in the dialplan as an explicit extension or a pattern match.
1044 */
1046 return NULL;
1047 }
1048
1049 if (ast_get_extension_name(hint_exten)[0] == '_') {
1050 /*
1051 * If this resolved down to a pattern match that means this is the first request
1052 * for this explicit extension so we need to add it to the dialplan which will create
1053 * an extension state for it. It's possible for us to conflict with another thread but
1054 * in that case the ast_add_extension call will fail and be a no-op and we will return
1055 * the extension state the other thread created.
1056 */
1060 ast_get_extension_registrar(hint_exten));
1061 }
1062
1063 /* The extension state should already exist at this point */
1064 snprintf(location, sizeof(location), "%s@%s", extension, q.foundcontext);
1066
1067 return ao2_find(extension_states, location, OBJ_SEARCH_KEY);
1068}
void ast_free_ptr(void *ptr)
free() wrapper
Definition astmm.c:1739
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition astobj2.h:1101
@ E_MATCH
Definition extconf.h:217
void * ast_get_extension_app_data(struct ast_exten *e)
Definition pbx.c:6720
int ast_add_extension(const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
Add and extension to an extension context.
Definition pbx.c:5206
int ast_wrlock_contexts(void)
Write locks the context list.
Definition pbx.c:6621
int ast_get_extension_matchcid(struct ast_exten *e)
Definition pbx.c:6705
const char * ast_get_extension_cidmatch(struct ast_exten *e)
Definition pbx.c:6710
const char * ast_get_extension_label(struct ast_exten *e)
Definition pbx.c:6672
#define PRIORITY_HINT
Definition pbx.h:54
struct ast_exten * pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action)
Definition ael_main.c:152
int ast_unlock_contexts(void)
Unlocks contexts.
Definition pbx.c:6631
const char * ast_get_extension_registrar(struct ast_exten *e)
Definition pbx.c:6690
ast_exten: An extension The dialplan is saved as a linked list with each context having it's own link...
Definition pbx.c:207
const char * foundcontext
Definition extconf.h:241

References ao2_find, ast_add_extension(), ast_free_ptr(), ast_get_extension_app(), ast_get_extension_app_data(), ast_get_extension_cidmatch(), ast_get_extension_label(), ast_get_extension_matchcid(), ast_get_extension_name(), ast_get_extension_registrar(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_strdup, ast_unlock_contexts(), ast_wrlock_contexts(), E_MATCH, extension_states, pbx_find_info::foundcontext, NULL, OBJ_SEARCH_KEY, pbx_find_extension(), PRIORITY_HINT, and pbx_find_info::stacklen.

Referenced by ast_extension_state_get_latest_device_snapshot(), ast_extension_state_get_latest_presence_snapshot(), and ast_extension_state_topic().

◆ extension_state_presence_snapshot_create()

static struct ast_extension_state_presence_snapshot * extension_state_presence_snapshot_create ( enum ast_presence_state  presence_state,
const char *  presence_subtype,
const char *  presence_message 
)
static

Definition at line 527 of file extension_state.c.

529{
530 struct ast_extension_state_presence_snapshot *presence_snapshot;
531
532 presence_snapshot = ao2_alloc_options(sizeof(*presence_snapshot), extension_state_presence_snapshot_destroy,
534 if (!presence_snapshot) {
535 return NULL;
536 }
537
538 /* To ensure that we don't give a partial snapshot we fail creation if any allocation fails */
539 presence_snapshot->presence_state = presence_state;
540 if (presence_subtype) {
541 presence_snapshot->presence_subtype = ast_strdup(presence_subtype);
542 if (!presence_snapshot->presence_subtype) {
543 ao2_ref(presence_snapshot, -1);
544 return NULL;
545 }
546 }
547 if (presence_message) {
548 presence_snapshot->presence_message = ast_strdup(presence_message);
549 if (!presence_snapshot->presence_message) {
550 ao2_ref(presence_snapshot, -1);
551 return NULL;
552 }
553 }
554
555 return presence_snapshot;
556}
static void extension_state_presence_snapshot_destroy(void *obj)
char * presence_subtype
The subtype of the presence state.
char * presence_message
An optional message for the presence.
enum ast_presence_state presence_state
The presence state of the extension.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_ref, ast_strdup, extension_state_presence_snapshot_destroy(), NULL, ast_extension_state_presence_snapshot::presence_message, ast_extension_state_presence_snapshot::presence_state, and ast_extension_state_presence_snapshot::presence_subtype.

Referenced by extension_state_alloc(), extension_state_presence_state_cb(), and extension_state_update_sources().

◆ extension_state_presence_snapshot_destroy()

static void extension_state_presence_snapshot_destroy ( void *  obj)
static

◆ extension_state_presence_state_cb()

static void extension_state_presence_state_cb ( void *  unused,
struct stasis_subscription sub,
struct stasis_message msg 
)
static

Definition at line 822 of file extension_state.c.

824{
825 struct ast_presence_state_message *presence_state;
826 struct ao2_iterator iter;
827 struct extension_state *state;
828
830 return;
831 }
832
833 presence_state = stasis_message_data(msg);
834
837 for (; (state = ao2_iterator_next(&iter)); ao2_ref(state, -1)) {
838 enum ast_presence_state presence_state_new;
839 char *presence_subtype, *presence_message;
840 struct ast_extension_state_presence_snapshot *presence_snapshot;
841 struct ast_extension_state_update_message *update_message;
842
844
845 /*
846 * We determine if this update is relevant to this extension state by seeing if the presence sources string
847 * even remotely contains the provider for this update. Worst case it's a substring and the calculated presence
848 * state is the same as before in which case we ignore it.
849 */
850 if (!state->presence_sources_string || !strcasestr(state->presence_sources_string, presence_state->provider)) {
852 continue;
853 }
854
855 /*
856 * Aggregation of presence state is done by requesting the current presence state with passing in a complete
857 * list of providers. This means that a presence state change message is just a notification to us to go and
858 * retrieve the new presence state. We don't just take it from the message itself. Since presence state is not
859 * as common as device state this is not a problem despite being inefficient in comparison to the device state
860 * implementation.
861 */
862 presence_state_new = ast_presence_state(state->presence_sources_string, &presence_subtype, &presence_message);
863 if (presence_state_new == AST_PRESENCE_INVALID) {
864 /* For the invalid case we just ignore this update */
866 continue;
867 }
868
869 if ((state->presence_snapshot->presence_state == presence_state_new) &&
870 ((!presence_subtype && !state->presence_snapshot->presence_subtype) ||
871 (presence_subtype && state->presence_snapshot->presence_subtype &&
872 !strcmp(presence_subtype, state->presence_snapshot->presence_subtype))) &&
873 ((!presence_message && !state->presence_snapshot->presence_message) ||
874 (presence_message && state->presence_snapshot->presence_message &&
875 !strcmp(presence_message, state->presence_snapshot->presence_message)))) {
876 /* No change in presence state, so ignore this update */
878 ast_free(presence_subtype);
879 ast_free(presence_message);
880 continue;
881 }
882
883 presence_snapshot = extension_state_presence_snapshot_create(presence_state_new, presence_subtype, presence_message);
884 if (!presence_snapshot) {
886 ast_free(presence_subtype);
887 ast_free(presence_message);
888 continue;
889 }
890
891 update_message = extension_state_update_message_create(state->dialplan_context,
892 state->dialplan_extension, state->device_snapshot, state->device_snapshot, state->presence_snapshot, presence_snapshot);
893 ao2_replace(state->presence_snapshot, presence_snapshot);
894 ao2_ref(presence_snapshot, -1);
895 if (update_message) {
897
898 if (message) {
899 stasis_publish(state->extension_state_topic, message);
900 ao2_ref(message, -1);
901 }
902
903 ao2_ref(update_message, -1);
904 }
905
907
908 ast_free(presence_subtype);
909 ast_free(presence_message);
910 }
913}
char * strcasestr(const char *, const char *)
ast_presence_state
@ AST_PRESENCE_INVALID
Stasis message payload representing a presence state update.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_replace, ao2_unlock, ast_extension_state_update_message_type(), ast_free, AST_PRESENCE_INVALID, ast_presence_state_message_type(), extension_state_presence_snapshot_create(), extension_state_update_message_create(), extension_states, stasis_message_create(), stasis_message_data(), stasis_publish(), and strcasestr().

Referenced by ast_extension_state_init().

◆ extension_state_remove_message_create()

static struct stasis_message * extension_state_remove_message_create ( const char *  context,
const char *  extension 
)
static

Definition at line 751 of file extension_state.c.

752{
753 size_t context_len = strlen(context) + 1;
754 size_t extension_len = strlen(extension) + 1;
755 struct ast_extension_state_remove_message *remove_message;
756 struct stasis_message *message;
757
758 remove_message = ao2_alloc_options(sizeof(*remove_message) + context_len + extension_len, NULL,
760 if (!remove_message) {
761 return NULL;
762 }
763
764 ast_copy_string(remove_message->extension, extension, extension_len); /* Safe */
765 remove_message->context = remove_message->extension + extension_len;
766 ast_copy_string(remove_message->context, context, context_len); /* Safe */
767
769 ao2_ref(remove_message, -1);
770
771 return message;
772}
Stasis message for extension state removal message.
char * context
The dialplan context.
char extension[0]
The dialplan extension.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_ref, ast_copy_string(), ast_extension_state_remove_message_type(), ast_extension_state_remove_message::context, ast_extension_state_remove_message::extension, NULL, and stasis_message_create().

Referenced by extension_state_shutdown().

◆ extension_state_shutdown()

static void extension_state_shutdown ( struct extension_state state)
static

Definition at line 783 of file extension_state.c.

784{
785 struct stasis_message *remove_message;
786
787 /*
788 * Shutting down an extension state requires us to publish to its topic so all subscribers
789 * know that it is going away. However, if the topic failed to be created then we have nothing
790 * to publish to and can just return.
791 */
792 if (!state->extension_state_topic) {
793 return;
794 }
795
796 /* Inform all subscribers that this extension state is being removed */
797 remove_message = extension_state_remove_message_create(state->dialplan_context,
798 state->dialplan_extension);
799 if (remove_message) {
800 stasis_publish(state->extension_state_topic, remove_message);
801 ao2_ref(remove_message, -1);
802 }
803
805 AST_VECTOR_FREE(&state->device_state_sources);
806
807 stasis_forward_cancel(state->extension_state_forwarder);
808}
static struct stasis_message * extension_state_remove_message_create(const char *context, const char *extension)
struct stasis_forward * stasis_forward_cancel(struct stasis_forward *forward)
Definition stasis.c:1626

References ao2_ref, AST_VECTOR_CALLBACK_VOID, AST_VECTOR_FREE, extension_state_device_source_destroy(), extension_state_remove_message_create(), stasis_forward_cancel(), and stasis_publish().

Referenced by extension_state_cleanup_individual(), and pbx_extension_state_hint_remove().

◆ extension_state_update_message_create()

static struct ast_extension_state_update_message * extension_state_update_message_create ( const char *  context,
const char *  extension,
struct ast_extension_state_device_snapshot old_device_snapshot,
struct ast_extension_state_device_snapshot new_device_snapshot,
struct ast_extension_state_presence_snapshot old_presence_snapshot,
struct ast_extension_state_presence_snapshot new_presence_snapshot 
)
static

Definition at line 190 of file extension_state.c.

194{
195 size_t context_len = strlen(context) + 1;
196 size_t extension_len = strlen(extension) + 1;
197 struct ast_extension_state_update_message *update_message;
198
199 update_message = ao2_alloc_options(sizeof(*update_message) + context_len + extension_len,
201 if (!update_message) {
202 return NULL;
203 }
204
205 ast_copy_string(update_message->extension, extension, extension_len); /* Safe */
206 update_message->context = update_message->extension + extension_len;
207 ast_copy_string(update_message->context, context, context_len); /* Safe */
208
213
214 return update_message;
215}
static void extension_state_update_message_destroy(void *obj)
char * context
The dialplan context.
struct ast_extension_state_presence_snapshot * old_presence_snapshot
The old presence snapshot.
char extension[0]
The dialplan extension.
struct ast_extension_state_device_snapshot * old_device_snapshot
The old device snapshot.
struct ast_extension_state_presence_snapshot * new_presence_snapshot
The new presence snapshot - will be pointer equivalent to old if unchanged.
struct ast_extension_state_device_snapshot * new_device_snapshot
The new device snapshot - will be pointer equivalent to old if unchanged.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_bump, ast_copy_string(), ast_extension_state_update_message::context, ast_extension_state_update_message::extension, extension_state_update_message_destroy(), ast_extension_state_update_message::new_device_snapshot, ast_extension_state_update_message::new_presence_snapshot, NULL, ast_extension_state_update_message::old_device_snapshot, and ast_extension_state_update_message::old_presence_snapshot.

Referenced by extension_state_device_state_cb(), extension_state_presence_state_cb(), and extension_state_update_sources().

◆ extension_state_update_message_destroy()

static void extension_state_update_message_destroy ( void *  obj)
static

◆ extension_state_update_sources()

static int extension_state_update_sources ( struct extension_state state,
struct ast_exten exten 
)
static

Definition at line 580 of file extension_state.c.

581{
582 struct ast_str *str = ast_str_thread_get(&hintdevice_data, HINTDEVICE_DATA_LENGTH);
583 char *devices, *device, *presence_state_sources;
584 struct ast_devstate_aggregate agg;
585 enum ast_extension_states new_device_state;
586 unsigned int version;
587 struct ast_extension_state_device_snapshot *device_snapshot = NULL;
588 struct ast_extension_state_presence_snapshot *presence_snapshot = NULL;
589
590 ast_str_set(&str, 0, "%s", ast_get_extension_app(exten));
592
594
595 /*
596 * The format of the app part of a hint is "[device[&device]],[presence[&presence]]" so
597 * we can just find the first occurrence of ',' in order to get to the presence sources.
598 */
599 presence_state_sources = strchr(devices, ',');
600 if (presence_state_sources) {
601 *presence_state_sources++ = '\0';
602 }
603
605
607
608 /* Devices are separated by '&' */
609 while ((device = strsep(&devices, "&"))) {
610 struct extension_state_device_source *source = NULL;
611 int i;
612
613 /* Skip any device names that are empty, as we can do nothing */
614 if (ast_strlen_zero(device)) {
615 continue;
616 }
617
618 for (i = 0; i < AST_VECTOR_SIZE(&state->device_state_sources); i++) {
619 struct extension_state_device_source *existing_source = AST_VECTOR_GET(&state->device_state_sources, i);
620
621 if (!strcmp(existing_source->info->device, device)) {
622 source = existing_source;
623 break;
624 }
625 }
626 if (!source) {
628 if (!source) {
630 return -1;
631 }
632 AST_VECTOR_APPEND(&state->device_state_sources, source);
633 }
634
635 ast_devstate_aggregate_add(&agg, source->info->state);
636 source->version = version;
637 }
638
639 /* Do a pass and remove all old device sources */
640 AST_VECTOR_REMOVE_ALL_CMP_UNORDERED(&state->device_state_sources, version,
642
643 /* If device state sources exist it is what produces the device state, otherwise we use the default */
644 if (AST_VECTOR_SIZE(&state->device_state_sources)) {
646 } else {
647 new_device_state = AST_EXTENSION_UNAVAILABLE;
648 }
649
650 /* If the device state has changed, create a new snapshot */
651 if (state->device_snapshot->state != new_device_state) {
652 device_snapshot = extension_state_device_snapshot_create(new_device_state, &state->device_state_sources, NULL);
653 }
654 if (!device_snapshot) {
655 /* If there's no new device snapshot we use the old one */
656 device_snapshot = state->device_snapshot;
657 }
658
659 /* If the presence state has changed, create a new snapshot */
660 if ((!state->presence_sources_string && presence_state_sources) ||
661 (state->presence_sources_string && strcmp(state->presence_sources_string, presence_state_sources))) {
662 enum ast_presence_state presence_state = AST_PRESENCE_NOT_SET;
663 char *presence_subtype = NULL, *presence_message = NULL;
664
665 ast_free(state->presence_sources_string);
666
667 if (!ast_strlen_zero(presence_state_sources)) {
668 state->presence_sources_string = ast_strdup(presence_state_sources);
669 /* Presence state is also separated by & but only the presence state API can handle it and aggregate */
670 presence_state = ast_presence_state(presence_state_sources, &presence_subtype,
671 &presence_message);
672 } else {
673 state->presence_sources_string = NULL;
674 }
675
676 presence_snapshot = extension_state_presence_snapshot_create(presence_state, presence_subtype, presence_message);
677
678 ast_free(presence_subtype);
679 ast_free(presence_message);
680 }
681 if (!presence_snapshot) {
682 /* If there's no new presence snapshot we use the old one */
683 presence_snapshot = state->presence_snapshot;
684 }
685
686 /* If any snapshots have changed create an update message containing them */
687 if (state->device_snapshot != device_snapshot || state->presence_snapshot != presence_snapshot) {
688 struct ast_extension_state_update_message *update_message;
689
690 update_message = extension_state_update_message_create(state->dialplan_context, state->dialplan_extension, state->device_snapshot,
691 device_snapshot, state->presence_snapshot, presence_snapshot);
692 if (update_message) {
694
695 if (message) {
696 stasis_publish(state->extension_state_topic, message);
697 ao2_ref(message, -1);
698 }
699
700 ao2_ref(update_message, -1);
701 }
702
703 /* If applicable, update the snapshots on the state to their new version */
704 if (state->device_snapshot != device_snapshot) {
705 ao2_replace(state->device_snapshot, device_snapshot);
706 ao2_ref(device_snapshot, -1);
707 }
708 if (state->presence_snapshot != presence_snapshot) {
709 ao2_replace(state->presence_snapshot, presence_snapshot);
710 ao2_ref(presence_snapshot, -1);
711 }
712 }
713
715
716 return 0;
717}
const char * str
Definition app_jack.c:150
char * strsep(char **str, const char *delims)
static char version[AST_MAX_EXTENSION]
static struct extension_state_device_source * extension_state_device_source_alloc(struct extension_state *state, const char *device)
#define HINTDEVICE_DATA_LENGTH
#define DEVICE_SOURCE_ELEM_VERSION_CMP(elem, value)
device source non-matching version comparator for AST_VECTOR_REMOVE_CMP_UNORDERED()
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition strings.h:1113
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition strings.h:909
Support for dynamic strings.
Definition strings.h:623
unsigned int version
The current version for this source.
long int ast_random(void)
Definition utils.c:2346
#define AST_VECTOR_REMOVE_ALL_CMP_UNORDERED(vec, value, cmp, cleanup)
Remove all elements from a vector that matches the given comparison.
Definition vector.h:472

References ao2_lock, ao2_ref, ao2_replace, ao2_unlock, ast_devstate_aggregate_add(), ast_devstate_aggregate_init(), ast_devstate_aggregate_result(), ast_devstate_to_extenstate(), ast_extension_state_update_message_type(), AST_EXTENSION_UNAVAILABLE, ast_free, ast_get_extension_app(), AST_PRESENCE_NOT_SET, ast_random(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_strdup, ast_strlen_zero(), AST_VECTOR_APPEND, AST_VECTOR_GET, AST_VECTOR_REMOVE_ALL_CMP_UNORDERED, AST_VECTOR_SIZE, ast_extension_state_device_state_info::device, DEVICE_SOURCE_ELEM_VERSION_CMP, extension_state_device_snapshot_create(), extension_state_device_source_alloc(), extension_state_device_source_destroy(), extension_state_presence_snapshot_create(), extension_state_update_message_create(), HINTDEVICE_DATA_LENGTH, extension_state_device_source::info, NULL, stasis_message_create(), stasis_publish(), ast_extension_state_device_state_info::state, str, strsep(), version, and extension_state_device_source::version.

Referenced by pbx_extension_state_hint_set().

◆ handle_show_hint()

static char * handle_show_hint ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1466 of file extension_state.c.

1467{
1468 struct extension_state *extstate;
1469 int num = 0, extenlen;
1470 struct ao2_iterator i;
1471
1472 switch (cmd) {
1473 case CLI_INIT:
1474 e->command = "core show hint";
1475 e->usage =
1476 "Usage: core show hint <exten>\n"
1477 " List registered hint.\n"
1478 " Hint details are shown in five columns. In order from left to right, they are:\n"
1479 " 1. Hint extension URI.\n"
1480 " 2. List of mapped device or presence state identifiers.\n"
1481 " 3. Current extension state. The aggregate of mapped device states.\n"
1482 " 4. Current presence state for the mapped presence state provider.\n"
1483 " 5. Watchers - number of subscriptions and other entities watching this hint.\n";
1484 return NULL;
1485 case CLI_GENERATE:
1486 return complete_core_show_hint(a->line, a->word, a->pos, a->n);
1487 }
1488
1489 if (a->argc < 4)
1490 return CLI_SHOWUSAGE;
1491
1493 ast_cli(a->fd, "There are no registered dialplan hints\n");
1494 return CLI_SUCCESS;
1495 }
1496
1497 extenlen = strlen(a->argv[3]);
1499 for (; (extstate = ao2_iterator_next(&i)); ao2_ref(extstate, -1)) {
1500 ao2_lock(extstate);
1501 if (!strncasecmp(extstate->extension, a->argv[3], extenlen)) {
1502 ast_cli(a->fd, "%-30.30s: %-60.60s State:%-15.15s Presence:%-15.15s Watchers %2zd\n",
1503 extstate->extension,
1504 extstate->hint_extension ? ast_get_extension_app(extstate->hint_extension) : "None",
1505 ast_extension_state2str(extstate->device_snapshot->state),
1506 ast_presence_state2str(extstate->presence_snapshot->presence_state),
1507 extstate->extension_state_topic ? stasis_topic_subscribers(extstate->extension_state_topic) : 0);
1508 num++;
1509 }
1510 ao2_unlock(extstate);
1511 }
1513 if (!num)
1514 ast_cli(a->fd, "No hints matching extension %s\n", a->argv[3]);
1515 else
1516 ast_cli(a->fd, "%d hint%s matching extension %s\n", num, (num!=1 ? "s":""), a->argv[3]);
1517 return CLI_SUCCESS;
1518}
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
static char * complete_core_show_hint(const char *line, const char *word, int pos, int state)
const char * ast_presence_state2str(enum ast_presence_state state)
Convert presence state to text string for output.
size_t stasis_topic_subscribers(const struct stasis_topic *topic)
Return the number of subscribers of a topic.
Definition stasis.c:710
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
char extension[0]
The combined extension this state is for (extension@context)
struct ast_exten * hint_extension
The dialplan hint that last configured this extension state.
static struct test_val a

References a, ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_cli(), ast_extension_state2str(), ast_get_extension_app(), ast_presence_state2str(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_core_show_hint(), extension_state::device_snapshot, extension_state::extension, extension_state::extension_state_topic, extension_states, extension_state::hint_extension, NULL, extension_state::presence_snapshot, ast_extension_state_presence_snapshot::presence_state, stasis_topic_subscribers(), ast_extension_state_device_snapshot::state, and ast_cli_entry::usage.

◆ handle_show_hints()

static char * handle_show_hints ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1365 of file extension_state.c.

1366{
1367 struct extension_state *state;
1368 int num = 0;
1369 struct ao2_iterator i;
1370
1371 switch (cmd) {
1372 case CLI_INIT:
1373 e->command = "core show hints";
1374 e->usage =
1375 "Usage: core show hints\n"
1376 " List registered hints.\n"
1377 " Hint details are shown in five columns. In order from left to right, they are:\n"
1378 " 1. Hint extension URI.\n"
1379 " 2. List of mapped device or presence state identifiers.\n"
1380 " 3. Current extension state. The aggregate of mapped device states.\n"
1381 " 4. Current presence state for the mapped presence state provider.\n"
1382 " 5. Watchers - number of subscriptions and other entities watching this hint.\n";
1383 return NULL;
1384 case CLI_GENERATE:
1385 return NULL;
1386 }
1387
1389 ast_cli(a->fd, "There are no registered dialplan hints\n");
1390 return CLI_SUCCESS;
1391 }
1392 /* ... we have hints ... */
1393 ast_cli(a->fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
1394
1396 for (; (state = ao2_iterator_next(&i)); ao2_ref(state, -1)) {
1397 ao2_lock(state);
1398 ast_cli(a->fd, "%-30.30s: %-60.60s State:%-15.15s Presence:%-15.15s Watchers %2zd\n",
1399 state->extension,
1400 state->hint_extension ? ast_get_extension_app(state->hint_extension) : "None",
1401 ast_extension_state2str(state->device_snapshot->state),
1402 ast_presence_state2str(state->presence_snapshot->presence_state),
1403 state->extension_state_topic ? stasis_topic_subscribers(state->extension_state_topic) : 0);
1405
1406 num++;
1407 }
1409
1410 ast_cli(a->fd, "----------------\n");
1411 ast_cli(a->fd, "- %d hints registered\n", num);
1412 return CLI_SUCCESS;
1413}

References a, ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_cli(), ast_extension_state2str(), ast_get_extension_app(), ast_presence_state2str(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, extension_states, NULL, stasis_topic_subscribers(), and ast_cli_entry::usage.

◆ pbx_extension_state_hint_remove()

void pbx_extension_state_hint_remove ( struct ast_exten exten,
struct ast_context context 
)

Definition at line 1269 of file extension_state.c.

1270{
1272 struct extension_state *state;
1273
1274 snprintf(extension, sizeof(extension), "%s@%s", ast_get_extension_name(exten), ast_get_context_name(context));
1275
1277
1279
1280 /* If this is not the latest hint extension that configured this extension state it can't remove it */
1281 if (!state || state->hint_extension != exten) {
1284 return;
1285 }
1286
1289 ao2_ref(state, -1);
1290
1292}
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
Definition astobj2.h:1600
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition astobj2.h:1063

References ao2_cleanup, ao2_find, ao2_lock, ao2_ref, ao2_unlink_flags, ao2_unlock, ast_get_context_name(), ast_get_extension_name(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, extension_state_shutdown(), extension_states, OBJ_NOLOCK, and OBJ_SEARCH_KEY.

Referenced by ast_change_hint(), and ast_remove_hint().

◆ pbx_extension_state_hint_set()

void pbx_extension_state_hint_set ( struct ast_exten exten,
struct ast_context context 
)

extension_state.c functions needed by pbx.c

Definition at line 1239 of file extension_state.c.

1240{
1242 struct extension_state *state;
1243
1244 snprintf(extension, sizeof(extension), "%s@%s", ast_get_extension_name(exten), ast_get_context_name(context));
1245
1247
1249 if (!state) {
1250 state = extension_state_alloc(exten, context);
1251 if (!state) {
1252 ast_log(LOG_WARNING, "Could not create extension state for hint '%s', it will be unavailable\n",
1253 extension);
1255 return;
1256 }
1258 }
1259
1260 state->hint_extension = exten;
1261 if (extension[0] != '_') {
1263 }
1264 ao2_ref(state, -1);
1265
1267}
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition astobj2.h:1554
static int extension_state_update_sources(struct extension_state *state, struct ast_exten *exten)
static struct extension_state * extension_state_alloc(struct ast_exten *exten, struct ast_context *context)
#define LOG_WARNING

References ao2_find, ao2_link_flags, ao2_lock, ao2_ref, ao2_unlock, ast_get_context_name(), ast_get_extension_name(), ast_log, AST_MAX_CONTEXT, AST_MAX_EXTENSION, extension_state_alloc(), extension_state_update_sources(), extension_states, LOG_WARNING, OBJ_NOLOCK, and OBJ_SEARCH_KEY.

Referenced by ast_add_hint(), ast_change_hint(), and context_promote().

◆ STASIS_MESSAGE_TYPE_DEFN() [1/2]

STASIS_MESSAGE_TYPE_DEFN ( ast_extension_state_remove_message_type  )

Stasis message type for extension state remove messages.

◆ STASIS_MESSAGE_TYPE_DEFN() [2/2]

STASIS_MESSAGE_TYPE_DEFN ( ast_extension_state_update_message_type  )

Sort function for extension states.

Compare function for extension states

Message type for extension state updates

Variable Documentation

◆ extension_state_cli

struct ast_cli_entry extension_state_cli[]
static
Initial value:
= {
{ .handler = handle_show_hints , .summary = "Show dialplan hints" ,},
{ .handler = handle_show_hint , .summary = "Show dialplan hint" ,},
}
static char * handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

Definition at line 1520 of file extension_state.c.

1520 {
1521 AST_CLI_DEFINE(handle_show_hints, "Show dialplan hints"),
1522 AST_CLI_DEFINE(handle_show_hint, "Show dialplan hint"),
1523};
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197

Referenced by ast_extension_state_init(), and extension_state_cleanup().

◆ extension_state_mappings

const struct cfextension_states extension_state_mappings[]
static

Referenced by ast_extension_state2str().

◆ extension_state_topic_all

struct stasis_topic* extension_state_topic_all
static

Topic which receives all extension state updates.

Definition at line 146 of file extension_state.c.

Referenced by ast_extension_state_init(), ast_extension_state_topic_all(), and extension_state_alloc().

◆ extension_states

struct ao2_container* extension_states
static

◆ presence_state_sub

struct stasis_subscription* presence_state_sub
static

Single presence state subscription, for all extension states.

Definition at line 149 of file extension_state.c.

Referenced by ast_extension_state_init(), and extension_state_cleanup().