Merge "res_pjsip_pubsub.c: Implement "pjsip show subscriptions" commands."
This commit is contained in:
commit
f114b7b8c9
|
@ -42,6 +42,7 @@
|
||||||
#include "asterisk/res_pjsip.h"
|
#include "asterisk/res_pjsip.h"
|
||||||
#include "asterisk/callerid.h"
|
#include "asterisk/callerid.h"
|
||||||
#include "asterisk/manager.h"
|
#include "asterisk/manager.h"
|
||||||
|
#include "asterisk/cli.h"
|
||||||
#include "asterisk/test.h"
|
#include "asterisk/test.h"
|
||||||
#include "res_pjsip/include/res_pjsip_private.h"
|
#include "res_pjsip/include/res_pjsip_private.h"
|
||||||
#include "asterisk/res_pjsip_presence_xml.h"
|
#include "asterisk/res_pjsip_presence_xml.h"
|
||||||
|
@ -3694,6 +3695,541 @@ static int ami_show_resource_lists(struct mansession *s, const struct message *m
|
||||||
#define AMI_SHOW_SUBSCRIPTIONS_INBOUND "PJSIPShowSubscriptionsInbound"
|
#define AMI_SHOW_SUBSCRIPTIONS_INBOUND "PJSIPShowSubscriptionsInbound"
|
||||||
#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND "PJSIPShowSubscriptionsOutbound"
|
#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND "PJSIPShowSubscriptionsOutbound"
|
||||||
|
|
||||||
|
#define MAX_REGEX_ERROR_LEN 128
|
||||||
|
|
||||||
|
struct cli_sub_parms {
|
||||||
|
/*! CLI handler entry e parameter */
|
||||||
|
struct ast_cli_entry *e;
|
||||||
|
/*! CLI handler entry a parameter */
|
||||||
|
struct ast_cli_args *a;
|
||||||
|
/*! CLI subscription entry output line(s) */
|
||||||
|
struct ast_str *buf;
|
||||||
|
/*! Compiled regular expression to select if buf is written to CLI when not NULL. */
|
||||||
|
regex_t *like;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cli_sub_complete_parms {
|
||||||
|
struct ast_cli_args *a;
|
||||||
|
/*! Found callid for search position */
|
||||||
|
char *callid;
|
||||||
|
int wordlen;
|
||||||
|
int which;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int cli_complete_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_complete_parms *cli)
|
||||||
|
{
|
||||||
|
pj_str_t *callid;
|
||||||
|
|
||||||
|
if (!sub_tree->dlg) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
callid = &sub_tree->dlg->call_id->id;
|
||||||
|
if (cli->wordlen <= pj_strlen(callid)
|
||||||
|
&& !strncasecmp(cli->a->word, pj_strbuf(callid), cli->wordlen)
|
||||||
|
&& (++cli->which > cli->a->n)) {
|
||||||
|
cli->callid = ast_malloc(pj_strlen(callid) + 1);
|
||||||
|
if (cli->callid) {
|
||||||
|
ast_copy_pj_str(cli->callid, callid, pj_strlen(callid) + 1);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cli_complete_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)
|
||||||
|
{
|
||||||
|
return sub_tree->role == AST_SIP_NOTIFIER
|
||||||
|
? cli_complete_subscription_common(sub_tree, arg) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cli_complete_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg)
|
||||||
|
{
|
||||||
|
return sub_tree->role == AST_SIP_SUBSCRIBER
|
||||||
|
? cli_complete_subscription_common(sub_tree, arg) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *cli_complete_subscription_callid(struct ast_cli_args *a)
|
||||||
|
{
|
||||||
|
struct cli_sub_complete_parms cli;
|
||||||
|
on_subscription_t on_subscription;
|
||||||
|
|
||||||
|
if (a->pos != 4) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcasecmp(a->argv[3], "inbound")) {
|
||||||
|
on_subscription = cli_complete_subscription_inbound;
|
||||||
|
} else if (!strcasecmp(a->argv[3], "outbound")) {
|
||||||
|
on_subscription = cli_complete_subscription_outbound;
|
||||||
|
} else {
|
||||||
|
/* Should never get here */
|
||||||
|
ast_assert(0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cli.a = a;
|
||||||
|
cli.callid = NULL;
|
||||||
|
cli.wordlen = strlen(a->word);
|
||||||
|
cli.which = 0;
|
||||||
|
for_each_subscription(on_subscription, &cli);
|
||||||
|
|
||||||
|
return cli.callid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cli_subscription_expiry(struct sip_subscription_tree *sub_tree)
|
||||||
|
{
|
||||||
|
int expiry;
|
||||||
|
|
||||||
|
expiry = sub_tree->persistence
|
||||||
|
? ast_tvdiff_ms(sub_tree->persistence->expires, ast_tvnow()) / 1000
|
||||||
|
: 0;
|
||||||
|
if (expiry < 0) {
|
||||||
|
/* Subscription expired */
|
||||||
|
expiry = 0;
|
||||||
|
}
|
||||||
|
return expiry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cli_show_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
|
||||||
|
{
|
||||||
|
const char *callid = (const char *) cli->buf;/* Member repurposed to pass in callid */
|
||||||
|
pj_str_t *sub_callid;
|
||||||
|
struct ast_str *buf;
|
||||||
|
char *src;
|
||||||
|
char *dest;
|
||||||
|
char *key;
|
||||||
|
char *value;
|
||||||
|
char *value_end;
|
||||||
|
int key_len;
|
||||||
|
int key_filler_width;
|
||||||
|
int value_len;
|
||||||
|
|
||||||
|
if (!sub_tree->dlg) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
sub_callid = &sub_tree->dlg->call_id->id;
|
||||||
|
if (pj_strcmp2(sub_callid, callid)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = ast_str_create(512);
|
||||||
|
if (!buf) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_cli(cli->a->fd,
|
||||||
|
"%-20s: %s\n"
|
||||||
|
"===========================================================================\n",
|
||||||
|
"ParameterName", "ParameterValue");
|
||||||
|
|
||||||
|
ast_str_append(&buf, 0, "Resource: %s\n", sub_tree->root->resource);
|
||||||
|
ast_str_append(&buf, 0, "Event: %s\n", sub_tree->root->handler->event_name);
|
||||||
|
ast_str_append(&buf, 0, "Expiry: %d\n", cli_subscription_expiry(sub_tree));
|
||||||
|
|
||||||
|
sip_subscription_to_ami(sub_tree, &buf);
|
||||||
|
|
||||||
|
/* Convert AMI \r\n to \n line terminators. */
|
||||||
|
src = strchr(ast_str_buffer(buf), '\r');
|
||||||
|
if (src) {
|
||||||
|
dest = src;
|
||||||
|
++src;
|
||||||
|
while (*src) {
|
||||||
|
if (*src == '\r') {
|
||||||
|
++src;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*dest++ = *src++;
|
||||||
|
}
|
||||||
|
*dest = '\0';
|
||||||
|
ast_str_update(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reformat AMI key value pairs to pretty columns */
|
||||||
|
key = ast_str_buffer(buf);
|
||||||
|
do {
|
||||||
|
value = strchr(key, ':');
|
||||||
|
if (!value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value_end = strchr(value, '\n');
|
||||||
|
if (!value_end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate field lengths */
|
||||||
|
key_len = value - key;
|
||||||
|
key_filler_width = 20 - key_len;
|
||||||
|
if (key_filler_width < 0) {
|
||||||
|
key_filler_width = 0;
|
||||||
|
}
|
||||||
|
value_len = value_end - value;
|
||||||
|
|
||||||
|
ast_cli(cli->a->fd, "%.*s%*s%.*s\n",
|
||||||
|
key_len, key, key_filler_width, "",
|
||||||
|
value_len, value);
|
||||||
|
|
||||||
|
key = value_end + 1;
|
||||||
|
} while (*key);
|
||||||
|
ast_cli(cli->a->fd, "\n");
|
||||||
|
|
||||||
|
ast_free(buf);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cli_show_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)
|
||||||
|
{
|
||||||
|
return sub_tree->role == AST_SIP_NOTIFIER
|
||||||
|
? cli_show_subscription_common(sub_tree, arg) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cli_show_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg)
|
||||||
|
{
|
||||||
|
return sub_tree->role == AST_SIP_SUBSCRIBER
|
||||||
|
? cli_show_subscription_common(sub_tree, arg) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *cli_show_subscription_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||||
|
{
|
||||||
|
on_subscription_t on_subscription;
|
||||||
|
struct cli_sub_parms cli;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case CLI_INIT:
|
||||||
|
e->command = "pjsip show subscription {inbound|outbound}";
|
||||||
|
e->usage = "Usage:\n"
|
||||||
|
" pjsip show subscription inbound <call-id>\n"
|
||||||
|
" pjsip show subscription outbound <call-id>\n"
|
||||||
|
" Show active subscription with the dialog call-id\n";
|
||||||
|
return NULL;
|
||||||
|
case CLI_GENERATE:
|
||||||
|
return cli_complete_subscription_callid(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a->argc != 5) {
|
||||||
|
return CLI_SHOWUSAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcasecmp(a->argv[3], "inbound")) {
|
||||||
|
on_subscription = cli_show_subscription_inbound;
|
||||||
|
} else if (!strcasecmp(a->argv[3], "outbound")) {
|
||||||
|
on_subscription = cli_show_subscription_outbound;
|
||||||
|
} else {
|
||||||
|
/* Should never get here */
|
||||||
|
ast_assert(0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the subscription with the specified call-id */
|
||||||
|
cli.a = a;
|
||||||
|
cli.e = e;
|
||||||
|
cli.buf = (void *) a->argv[4];/* Repurpose the buf member to pass in callid */
|
||||||
|
for_each_subscription(on_subscription, &cli);
|
||||||
|
|
||||||
|
return CLI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CLI_SHOW_SUB_FORMAT_HEADER \
|
||||||
|
"Endpoint: <Endpoint/Caller-ID.............................................>\n" \
|
||||||
|
"Resource: <Resource/Event.................................................>\n" \
|
||||||
|
" Expiry: <Expiry> <Call-id..............................................>\n" \
|
||||||
|
"===========================================================================\n\n"
|
||||||
|
#define CLI_SHOW_SUB_FORMAT_ENTRY \
|
||||||
|
"Endpoint: %s/%s\n" \
|
||||||
|
"Resource: %s/%s\n" \
|
||||||
|
" Expiry: %8d %s\n\n"
|
||||||
|
|
||||||
|
static int cli_show_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
|
||||||
|
{
|
||||||
|
char caller_id[256];
|
||||||
|
char callid[256];
|
||||||
|
|
||||||
|
ast_callerid_merge(caller_id, sizeof(caller_id),
|
||||||
|
S_COR(sub_tree->endpoint->id.self.name.valid,
|
||||||
|
sub_tree->endpoint->id.self.name.str, NULL),
|
||||||
|
S_COR(sub_tree->endpoint->id.self.number.valid,
|
||||||
|
sub_tree->endpoint->id.self.number.str, NULL),
|
||||||
|
"<none>");
|
||||||
|
|
||||||
|
/* Call-id */
|
||||||
|
if (sub_tree->dlg) {
|
||||||
|
ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
|
||||||
|
} else {
|
||||||
|
ast_copy_string(callid, "<unknown>", sizeof(callid));
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_str_set(&cli->buf, 0, CLI_SHOW_SUB_FORMAT_ENTRY,
|
||||||
|
ast_sorcery_object_get_id(sub_tree->endpoint), caller_id,
|
||||||
|
sub_tree->root->resource, sub_tree->root->handler->event_name,
|
||||||
|
cli_subscription_expiry(sub_tree), callid);
|
||||||
|
|
||||||
|
if (cli->like) {
|
||||||
|
if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
|
||||||
|
/* Output line did not match the regex */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
|
||||||
|
++cli->count;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cli_show_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)
|
||||||
|
{
|
||||||
|
return sub_tree->role == AST_SIP_NOTIFIER
|
||||||
|
? cli_show_subscriptions_detail(sub_tree, arg) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cli_show_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
|
||||||
|
{
|
||||||
|
return sub_tree->role == AST_SIP_SUBSCRIBER
|
||||||
|
? cli_show_subscriptions_detail(sub_tree, arg) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *cli_show_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||||
|
{
|
||||||
|
on_subscription_t on_subscription;
|
||||||
|
struct cli_sub_parms cli;
|
||||||
|
regex_t like;
|
||||||
|
const char *regex;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case CLI_INIT:
|
||||||
|
e->command = "pjsip show subscriptions {inbound|outbound} [like]";
|
||||||
|
e->usage = "Usage:\n"
|
||||||
|
" pjsip show subscriptions inbound [like <regex>]\n"
|
||||||
|
" Show active inbound subscriptions\n"
|
||||||
|
" pjsip show subscriptions outbound [like <regex>]\n"
|
||||||
|
" Show active outbound subscriptions\n"
|
||||||
|
"\n"
|
||||||
|
" The regex selects a subscriptions output that matches.\n"
|
||||||
|
" i.e., All output lines for a subscription are checked\n"
|
||||||
|
" as a block by the regex.\n";
|
||||||
|
return NULL;
|
||||||
|
case CLI_GENERATE:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a->argc != 4 && a->argc != 6) {
|
||||||
|
return CLI_SHOWUSAGE;
|
||||||
|
}
|
||||||
|
if (!strcasecmp(a->argv[3], "inbound")) {
|
||||||
|
on_subscription = cli_show_subscriptions_inbound;
|
||||||
|
} else if (!strcasecmp(a->argv[3], "outbound")) {
|
||||||
|
on_subscription = cli_show_subscriptions_outbound;
|
||||||
|
} else {
|
||||||
|
/* Should never get here */
|
||||||
|
ast_assert(0);
|
||||||
|
return CLI_SHOWUSAGE;
|
||||||
|
}
|
||||||
|
if (a->argc == 6) {
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (strcasecmp(a->argv[4], "like")) {
|
||||||
|
return CLI_SHOWUSAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup regular expression */
|
||||||
|
memset(&like, 0, sizeof(like));
|
||||||
|
cli.like = &like;
|
||||||
|
regex = a->argv[5];
|
||||||
|
rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
|
||||||
|
if (rc) {
|
||||||
|
char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
|
||||||
|
|
||||||
|
regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
|
||||||
|
ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
|
||||||
|
regex, regerr);
|
||||||
|
return CLI_FAILURE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cli.like = NULL;
|
||||||
|
regex = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cli.a = a;
|
||||||
|
cli.e = e;
|
||||||
|
cli.count = 0;
|
||||||
|
cli.buf = ast_str_create(256);
|
||||||
|
if (!cli.buf) {
|
||||||
|
if (cli.like) {
|
||||||
|
regfree(cli.like);
|
||||||
|
}
|
||||||
|
return CLI_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_cli(a->fd, CLI_SHOW_SUB_FORMAT_HEADER);
|
||||||
|
for_each_subscription(on_subscription, &cli);
|
||||||
|
ast_cli(a->fd, "%d active subscriptions%s%s%s\n",
|
||||||
|
cli.count,
|
||||||
|
regex ? " matched \"" : "",
|
||||||
|
regex ?: "",
|
||||||
|
regex ? "\"" : "");
|
||||||
|
|
||||||
|
ast_free(cli.buf);
|
||||||
|
if (cli.like) {
|
||||||
|
regfree(cli.like);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CLI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CLI_LIST_SUB_FORMAT_HEADER "%-30.30s %-30.30s %6.6s %s\n"
|
||||||
|
#define CLI_LIST_SUB_FORMAT_ENTRY "%-30.30s %-30.30s %6d %s\n"
|
||||||
|
|
||||||
|
static int cli_list_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
|
||||||
|
{
|
||||||
|
char ep_cid_buf[50];
|
||||||
|
char res_evt_buf[50];
|
||||||
|
char callid[256];
|
||||||
|
|
||||||
|
/* Endpoint/CID column */
|
||||||
|
snprintf(ep_cid_buf, sizeof(ep_cid_buf), "%s/%s",
|
||||||
|
ast_sorcery_object_get_id(sub_tree->endpoint),
|
||||||
|
S_COR(sub_tree->endpoint->id.self.name.valid, sub_tree->endpoint->id.self.name.str,
|
||||||
|
S_COR(sub_tree->endpoint->id.self.number.valid,
|
||||||
|
sub_tree->endpoint->id.self.number.str, "<none>")));
|
||||||
|
|
||||||
|
/* Resource/Event column */
|
||||||
|
snprintf(res_evt_buf, sizeof(res_evt_buf), "%s/%s",
|
||||||
|
sub_tree->root->resource,
|
||||||
|
sub_tree->root->handler->event_name);
|
||||||
|
|
||||||
|
/* Call-id column */
|
||||||
|
if (sub_tree->dlg) {
|
||||||
|
ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
|
||||||
|
} else {
|
||||||
|
ast_copy_string(callid, "<unknown>", sizeof(callid));
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_str_set(&cli->buf, 0, CLI_LIST_SUB_FORMAT_ENTRY,
|
||||||
|
ep_cid_buf,
|
||||||
|
res_evt_buf,
|
||||||
|
cli_subscription_expiry(sub_tree),
|
||||||
|
callid);
|
||||||
|
|
||||||
|
if (cli->like) {
|
||||||
|
if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
|
||||||
|
/* Output line did not match the regex */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
|
||||||
|
++cli->count;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cli_list_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)
|
||||||
|
{
|
||||||
|
return sub_tree->role == AST_SIP_NOTIFIER
|
||||||
|
? cli_list_subscriptions_detail(sub_tree, arg) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cli_list_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
|
||||||
|
{
|
||||||
|
return sub_tree->role == AST_SIP_SUBSCRIBER
|
||||||
|
? cli_list_subscriptions_detail(sub_tree, arg) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *cli_list_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||||
|
{
|
||||||
|
on_subscription_t on_subscription;
|
||||||
|
struct cli_sub_parms cli;
|
||||||
|
regex_t like;
|
||||||
|
const char *regex;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case CLI_INIT:
|
||||||
|
e->command = "pjsip list subscriptions {inbound|outbound} [like]";
|
||||||
|
e->usage = "Usage:\n"
|
||||||
|
" pjsip list subscriptions inbound [like <regex>]\n"
|
||||||
|
" List active inbound subscriptions\n"
|
||||||
|
" pjsip list subscriptions outbound [like <regex>]\n"
|
||||||
|
" List active outbound subscriptions\n"
|
||||||
|
"\n"
|
||||||
|
" The regex selects output lines that match.\n";
|
||||||
|
return NULL;
|
||||||
|
case CLI_GENERATE:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a->argc != 4 && a->argc != 6) {
|
||||||
|
return CLI_SHOWUSAGE;
|
||||||
|
}
|
||||||
|
if (!strcasecmp(a->argv[3], "inbound")) {
|
||||||
|
on_subscription = cli_list_subscriptions_inbound;
|
||||||
|
} else if (!strcasecmp(a->argv[3], "outbound")) {
|
||||||
|
on_subscription = cli_list_subscriptions_outbound;
|
||||||
|
} else {
|
||||||
|
/* Should never get here */
|
||||||
|
ast_assert(0);
|
||||||
|
return CLI_SHOWUSAGE;
|
||||||
|
}
|
||||||
|
if (a->argc == 6) {
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (strcasecmp(a->argv[4], "like")) {
|
||||||
|
return CLI_SHOWUSAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup regular expression */
|
||||||
|
memset(&like, 0, sizeof(like));
|
||||||
|
cli.like = &like;
|
||||||
|
regex = a->argv[5];
|
||||||
|
rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
|
||||||
|
if (rc) {
|
||||||
|
char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
|
||||||
|
|
||||||
|
regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
|
||||||
|
ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
|
||||||
|
regex, regerr);
|
||||||
|
return CLI_FAILURE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cli.like = NULL;
|
||||||
|
regex = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cli.a = a;
|
||||||
|
cli.e = e;
|
||||||
|
cli.count = 0;
|
||||||
|
cli.buf = ast_str_create(256);
|
||||||
|
if (!cli.buf) {
|
||||||
|
if (cli.like) {
|
||||||
|
regfree(cli.like);
|
||||||
|
}
|
||||||
|
return CLI_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_cli(a->fd, CLI_LIST_SUB_FORMAT_HEADER,
|
||||||
|
"Endpoint/CLI", "Resource/Event", "Expiry", "Call-id");
|
||||||
|
for_each_subscription(on_subscription, &cli);
|
||||||
|
ast_cli(a->fd, "\n%d active subscriptions%s%s%s\n",
|
||||||
|
cli.count,
|
||||||
|
regex ? " matched \"" : "",
|
||||||
|
regex ?: "",
|
||||||
|
regex ? "\"" : "");
|
||||||
|
|
||||||
|
ast_free(cli.buf);
|
||||||
|
if (cli.like) {
|
||||||
|
regfree(cli.like);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CLI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ast_cli_entry cli_commands[] = {
|
||||||
|
AST_CLI_DEFINE(cli_list_subscriptions_inout, "List active inbound/outbound subscriptions"),
|
||||||
|
AST_CLI_DEFINE(cli_show_subscription_inout, "Show active subscription details"),
|
||||||
|
AST_CLI_DEFINE(cli_show_subscriptions_inout, "Show active inbound/outbound subscriptions"),
|
||||||
|
};
|
||||||
|
|
||||||
static int persistence_endpoint_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
|
static int persistence_endpoint_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
|
||||||
{
|
{
|
||||||
struct subscription_persistence *persistence = obj;
|
struct subscription_persistence *persistence = obj;
|
||||||
|
@ -4635,6 +5171,8 @@ static int load_module(void)
|
||||||
ast_manager_register_xml("PJSIPShowResourceLists", EVENT_FLAG_SYSTEM,
|
ast_manager_register_xml("PJSIPShowResourceLists", EVENT_FLAG_SYSTEM,
|
||||||
ami_show_resource_lists);
|
ami_show_resource_lists);
|
||||||
|
|
||||||
|
ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
|
||||||
|
|
||||||
AST_TEST_REGISTER(resource_tree);
|
AST_TEST_REGISTER(resource_tree);
|
||||||
AST_TEST_REGISTER(complex_resource_tree);
|
AST_TEST_REGISTER(complex_resource_tree);
|
||||||
AST_TEST_REGISTER(bad_resource);
|
AST_TEST_REGISTER(bad_resource);
|
||||||
|
@ -4648,6 +5186,16 @@ static int load_module(void)
|
||||||
|
|
||||||
static int unload_module(void)
|
static int unload_module(void)
|
||||||
{
|
{
|
||||||
|
AST_TEST_UNREGISTER(resource_tree);
|
||||||
|
AST_TEST_UNREGISTER(complex_resource_tree);
|
||||||
|
AST_TEST_UNREGISTER(bad_resource);
|
||||||
|
AST_TEST_UNREGISTER(bad_branch);
|
||||||
|
AST_TEST_UNREGISTER(duplicate_resource);
|
||||||
|
AST_TEST_UNREGISTER(loop);
|
||||||
|
AST_TEST_UNREGISTER(bad_event);
|
||||||
|
|
||||||
|
ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
|
||||||
|
|
||||||
ast_manager_unregister(AMI_SHOW_SUBSCRIPTIONS_OUTBOUND);
|
ast_manager_unregister(AMI_SHOW_SUBSCRIPTIONS_OUTBOUND);
|
||||||
ast_manager_unregister(AMI_SHOW_SUBSCRIPTIONS_INBOUND);
|
ast_manager_unregister(AMI_SHOW_SUBSCRIPTIONS_INBOUND);
|
||||||
ast_manager_unregister("PJSIPShowResourceLists");
|
ast_manager_unregister("PJSIPShowResourceLists");
|
||||||
|
@ -4657,14 +5205,6 @@ static int unload_module(void)
|
||||||
ast_sched_context_destroy(sched);
|
ast_sched_context_destroy(sched);
|
||||||
}
|
}
|
||||||
|
|
||||||
AST_TEST_UNREGISTER(resource_tree);
|
|
||||||
AST_TEST_UNREGISTER(complex_resource_tree);
|
|
||||||
AST_TEST_UNREGISTER(bad_resource);
|
|
||||||
AST_TEST_UNREGISTER(bad_branch);
|
|
||||||
AST_TEST_UNREGISTER(duplicate_resource);
|
|
||||||
AST_TEST_UNREGISTER(loop);
|
|
||||||
AST_TEST_UNREGISTER(bad_event);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue