]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_pjsip: Add "like" processing to pjsip list and show commands 57/1457/7
authorGeorge Joseph <george.joseph@fairview5.com>
Tue, 20 Oct 2015 21:02:30 +0000 (15:02 -0600)
committerGeorge Joseph <george.joseph@fairview5.com>
Sat, 24 Oct 2015 16:00:30 +0000 (10:00 -0600)
Add the ability to filter output from pjsip list and show commands
using the "like" predicate like chan_sip.

For endpoints, aors, auths, registrations, identifyies and transports,
the modification was a simple change of an ast_sorcery_retrieve_by_fields
call to ast_sorcery_retrieve_by_regex.  For channels and contacts a
little more work had to be done because neither of those objects are
true sorcery objects.  That was just removing the non-matching object
from the final container.  Of course, a little extra plumbing in the
common pjsip_cli code was needed to parse the "like" and pass the regex
to the get_container callbacks.

Some of the get_container code in res_pjsip_endpoint_identifier was also
refactored for simplicity.

ASTERISK-25477 #close
Reported by: Bryant Zimmerman
Tested by: George Joseph

Change-Id: I646d9326b778aac26bb3e2bcd7fa1346d24434f1

CHANGES
include/asterisk/res_pjsip_cli.h
res/res_pjsip/config_auth.c
res/res_pjsip/config_transport.c
res/res_pjsip/location.c
res/res_pjsip/pjsip_cli.c
res/res_pjsip/pjsip_configuration.c
res/res_pjsip_endpoint_identifier_ip.c
res/res_pjsip_outbound_registration.c

diff --git a/CHANGES b/CHANGES
index 1deba235d6104de4784425b8750aa9dc31066d52..044605cc52108500b48260d72c7ce847aed53a64 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -27,6 +27,11 @@ res_pjsip_outbound_registration
   outbound registration, registration is retried at the given interval up to
   'max_retries'.
 
+res_pjsip
+------------------
+ * The ability to use "like" has been added to the pjsip list and show
+   CLI commands.  For instance: CLI> pjsip list endpoints like abc
+
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 13.5.0 to Asterisk 13.6.0 ------------
 ------------------------------------------------------------------------------
index 44979b701e663ebe692fb5a2f608ef24d4945b55..c2535218ac23c061e8ce86949277515393f956ed 100644 (file)
@@ -61,7 +61,7 @@ struct ast_sip_cli_formatter_entry {
        /*! The callback used to print the details of the object. */
        ao2_callback_fn *print_body;
        /*! The function used to retrieve a container of all objects of this type. */
-       struct ao2_container *(* get_container)(void);
+       struct ao2_container *(* get_container)(const char *regex);
        /*! The function used to iterate over a container of objects. */
        int (* iterate)(void *container, ao2_callback_fn callback, void *args);
        /*! The function used to retrieve a specific object from it's container. */
index 773889c7a7df6d0d855df74c6f62b7ccbd5f9aa1..9160e6709cb6c9092c692534d44ca54a5dd7230a 100644 (file)
@@ -195,13 +195,12 @@ static struct ast_sip_endpoint_formatter endpoint_auth_formatter = {
        .format_ami = format_ami_endpoint_auth
 };
 
-static struct ao2_container *cli_get_container(void)
+static struct ao2_container *cli_get_container(const char *regex)
 {
        RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
        struct ao2_container *s_container;
 
-       container = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "auth",
-               AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+       container = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "auth", regex);
        if (!container) {
                return NULL;
        }
@@ -272,12 +271,14 @@ static int cli_print_body(void *obj, void *arg, int flags)
 static struct ast_cli_entry cli_commands[] = {
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Auths",
                .command = "pjsip list auths",
-               .usage = "Usage: pjsip list auths\n"
-                                "       List the configured PJSIP Auths\n"),
+               .usage = "Usage: pjsip list auths [ like <pattern> ]\n"
+                               "       List the configured PJSIP Auths\n"
+                               "       Optional regular expression pattern is used to filter the list.\n"),
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Auths",
                .command = "pjsip show auths",
-               .usage = "Usage: pjsip show auths\n"
-                                "       Show the configured PJSIP Auths\n"),
+               .usage = "Usage: pjsip show auths [ like <pattern> ]\n"
+                               "       Show the configured PJSIP Auths\n"
+                               "       Optional regular expression pattern is used to filter the list.\n"),
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Auth",
                .command = "pjsip show auth",
                .usage = "Usage: pjsip show auth <id>\n"
index 73030b155913bcd193a2d48fec89647fb00f48e1..e9986612c6a61438f3b213d345c242e0ff8979d0 100644 (file)
@@ -633,13 +633,13 @@ static int tos_to_str(const void *obj, const intptr_t *args, char **buf)
        return 0;
 }
 
-static struct ao2_container *cli_get_container(void)
+static struct ao2_container *cli_get_container(const char *regex)
 {
        RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
        struct ao2_container *s_container;
 
-       container = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport",
-               AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+       container = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "transport",
+               regex);
        if (!container) {
                return NULL;
        }
@@ -720,12 +720,14 @@ static struct ast_cli_entry cli_commands[] = {
        AST_CLI_DEFINE(handle_pjsip_list_ciphers, "List available OpenSSL cipher names"),
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Transports",
                .command = "pjsip list transports",
-               .usage = "Usage: pjsip list transports\n"
-                                "       List the configured PJSIP Transports\n"),
+               .usage = "Usage: pjsip list transports [ like <pattern> ]\n"
+                               "       List the configured PJSIP Transports\n"
+                               "       Optional regular expression pattern is used to filter the list.\n"),
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Transports",
                .command = "pjsip show transports",
-               .usage = "Usage: pjsip show transports\n"
-                                "       Show the configured PJSIP Transport\n"),
+               .usage = "Usage: pjsip show transports [ like <pattern> ]\n"
+                               "       Show the configured PJSIP Transport\n"
+                               "       Optional regular expression pattern is used to filter the list.\n"),
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Transport",
                .command = "pjsip show transport",
                .usage = "Usage: pjsip show transport <id>\n"
index 331d839a1ebfb1cc6b719a4ee07afd0d6423fc60..b6f88d20d43a92402a68c03b1407ab43b4d679d3 100644 (file)
@@ -594,13 +594,12 @@ struct ast_sip_endpoint_formatter endpoint_aor_formatter = {
        .format_ami = format_ami_endpoint_aor
 };
 
-static struct ao2_container *cli_aor_get_container(void)
+static struct ao2_container *cli_aor_get_container(const char *regex)
 {
        RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
        struct ao2_container *s_container;
 
-       container = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "aor",
-               AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+       container = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "aor", regex);
        if (!container) {
                return NULL;
        }
@@ -698,12 +697,25 @@ static int cli_contact_iterate(void *container, ao2_callback_fn callback, void *
        return ast_sip_for_each_contact(container, callback, args);
 }
 
-static struct ao2_container *cli_contact_get_container(void)
+static int cli_filter_contacts(void *obj, void *arg, int flags)
+{
+       struct ast_sip_contact_wrapper *wrapper = obj;
+       regex_t *regexbuf = arg;
+
+       if (!regexec(regexbuf, wrapper->contact_id, 0, NULL, 0)) {
+               return 0;
+       }
+
+       return CMP_MATCH;
+}
+
+static struct ao2_container *cli_contact_get_container(const char *regex)
 {
        RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
        struct ao2_container *child_container;
+       regex_t regexbuf;
 
-       parent_container =  cli_aor_get_container();
+       parent_container =  cli_aor_get_container("");
        if (!parent_container) {
                return NULL;
        }
@@ -716,12 +728,23 @@ static struct ao2_container *cli_contact_get_container(void)
 
        ao2_callback(parent_container, OBJ_NODATA, cli_aor_gather_contacts, child_container);
 
+       if (!ast_strlen_zero(regex)) {
+               if (regcomp(&regexbuf, regex, REG_EXTENDED | REG_NOSUB)) {
+                       ao2_ref(child_container, -1);
+                       return NULL;
+               }
+               ao2_callback(child_container, OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA, cli_filter_contacts, &regexbuf);
+               regfree(&regexbuf);
+       }
+
        return child_container;
 }
 
 static void *cli_contact_retrieve_by_id(const char *id)
 {
-       return ao2_find(cli_contact_get_container(), id, OBJ_KEY | OBJ_NOLOCK);
+       RAII_VAR(struct ao2_container *, container, cli_contact_get_container(""), ao2_cleanup);
+
+       return ao2_find(container, id, OBJ_KEY | OBJ_NOLOCK);
 }
 
 static int cli_contact_print_header(void *obj, void *arg, int flags)
@@ -858,12 +881,14 @@ static int cli_aor_print_body(void *obj, void *arg, int flags)
 static struct ast_cli_entry cli_commands[] = {
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Aors",
                .command = "pjsip list aors",
-               .usage = "Usage: pjsip list aors\n"
-                                "       List the configured PJSIP Aors\n"),
+               .usage = "Usage: pjsip list aors [ like <pattern> ]\n"
+                               "       List the configured PJSIP Aors\n"
+                               "       Optional regular expression pattern is used to filter the list.\n"),
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Aors",
                .command = "pjsip show aors",
-               .usage = "Usage: pjsip show aors\n"
-                                "       Show the configured PJSIP Aors\n"),
+               .usage = "Usage: pjsip show aors [ like <pattern> ]\n"
+                               "       Show the configured PJSIP Aors\n"
+                               "       Optional regular expression pattern is used to filter the list.\n"),
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Aor",
                .command = "pjsip show aor",
                .usage = "Usage: pjsip show aor <id>\n"
@@ -871,12 +896,14 @@ static struct ast_cli_entry cli_commands[] = {
 
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Contacts",
                .command = "pjsip list contacts",
-               .usage = "Usage: pjsip list contacts\n"
-                                "       List the configured PJSIP contacts\n"),
+               .usage = "Usage: pjsip list contacts [ like <pattern> ]\n"
+                               "       List the configured PJSIP contacts\n"
+                               "       Optional regular expression pattern is used to filter the list.\n"),
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Contacts",
                .command = "pjsip show contacts",
-               .usage = "Usage: pjsip show contacts\n"
-                                "       Show the configured PJSIP contacts\n"),
+               .usage = "Usage: pjsip show contacts [ like <pattern> ]\n"
+                               "       Show the configured PJSIP contacts\n"
+                               "       Optional regular expression pattern is used to filter the list.\n"),
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Contact",
                .command = "pjsip show contact",
                .usage = "Usage: pjsip show contact\n"
index 16df3f59c8da757d539ec4b03fd588221ef041f1..bbd0ac4b877a5a1f333248ee8e411b632d24bcfb 100644 (file)
@@ -125,6 +125,7 @@ char *ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_
        const char *cmd2;
        const char *object_id;
        char formatter_type[64];
+       const char *regex;
 
        struct ast_sip_cli_context context = {
                .indent_level = 0,
@@ -162,6 +163,18 @@ char *ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_
                is_container = 1;
        }
 
+       if (cmd != CLI_GENERATE
+               && is_container
+               && a->argc >= 4
+               && strcmp(object_id, "like") == 0) {
+               if (ast_strlen_zero(a->argv[4])) {
+                       return CLI_SHOWUSAGE;
+               }
+               regex = a->argv[4];
+       } else {
+               regex = "";
+       }
+
        if (cmd == CLI_GENERATE
                && (is_container
                        || a->argc > 4
@@ -187,7 +200,7 @@ char *ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_
                " =========================================================================================\n\n");
 
        if (is_container || cmd == CLI_GENERATE) {
-               container = formatter_entry->get_container();
+               container = formatter_entry->get_container(regex);
                if (!container) {
                        ast_cli(a->fd, "No container returned for object type %s.\n",
                                formatter_type);
index bcbb791e63acaa7d4efc53b27e7f0e27c60bc1f0..5d9097023982edd021bce1cbf6355e641d092498 100644 (file)
@@ -1395,13 +1395,12 @@ static int ami_show_endpoints(struct mansession *s, const struct message *m)
        return 0;
 }
 
-static struct ao2_container *cli_endpoint_get_container(void)
+static struct ao2_container *cli_endpoint_get_container(const char *regex)
 {
        RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
        struct ao2_container *s_container;
 
-       container = ast_sorcery_retrieve_by_fields(sip_sorcery, "endpoint",
-               AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+       container = ast_sorcery_retrieve_by_regex(sip_sorcery, "endpoint", regex);
        if (!container) {
                return NULL;
        }
@@ -1515,12 +1514,26 @@ static int cli_endpoint_gather_channels(void *obj, void *arg, int flags)
        return 0;
 }
 
-static struct ao2_container *cli_channel_get_container(void)
+static int cli_filter_channels(void *obj, void *arg, int flags)
+{
+       struct ast_channel_snapshot *channel = obj;
+       regex_t *regexbuf = arg;
+
+       if (!regexec(regexbuf, channel->name, 0, NULL, 0)
+               || !regexec(regexbuf, channel->appl, 0, NULL, 0)) {
+               return 0;
+       }
+
+       return CMP_MATCH;
+}
+
+static struct ao2_container *cli_channel_get_container(const char *regex)
 {
        RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
        struct ao2_container *child_container;
+       regex_t regexbuf;
 
-       parent_container = cli_endpoint_get_container();
+       parent_container = cli_endpoint_get_container("");
        if (!parent_container) {
                return NULL;
        }
@@ -1532,6 +1545,15 @@ static struct ao2_container *cli_channel_get_container(void)
 
        ao2_callback(parent_container, OBJ_NODATA, cli_endpoint_gather_channels, child_container);
 
+       if (!ast_strlen_zero(regex)) {
+               if (regcomp(&regexbuf, regex, REG_EXTENDED | REG_NOSUB)) {
+                       ao2_ref(child_container, -1);
+                       return NULL;
+               }
+               ao2_callback(child_container, OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA, cli_filter_channels, &regexbuf);
+               regfree(&regexbuf);
+       }
+
        return child_container;
 }
 
@@ -1544,7 +1566,7 @@ static const char *cli_channel_get_id(const void *obj)
 
 static void *cli_channel_retrieve_by_id(const char *id)
 {
-       RAII_VAR(struct ao2_container *, container, cli_channel_get_container(), ao2_cleanup);
+       RAII_VAR(struct ao2_container *, container, cli_channel_get_container(""), ao2_cleanup);
 
        return ao2_find(container, id, OBJ_KEY | OBJ_NOLOCK);
 }
@@ -1746,12 +1768,14 @@ static int cli_endpoint_print_body(void *obj, void *arg, int flags)
 static struct ast_cli_entry cli_commands[] = {
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Channels",
                .command = "pjsip list channels",
-               .usage = "Usage: pjsip list channels\n"
-                                "       List the active PJSIP channels\n"),
+               .usage = "Usage: pjsip list channels [ like <pattern> ]\n"
+                               "       List the active PJSIP channels\n"
+                               "       Optional regular expression pattern is used to filter the list.\n"),
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channels",
                .command = "pjsip show channels",
-               .usage = "Usage: pjsip show channels\n"
-                                "       List(detailed) the active PJSIP channels\n"),
+               .usage = "Usage: pjsip show channels [ like <pattern> ]\n"
+                               "       List(detailed) the active PJSIP channels\n"
+                               "       Optional regular expression pattern is used to filter the list.\n"),
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channel",
                .command = "pjsip show channel",
                .usage = "Usage: pjsip show channel\n"
@@ -1759,12 +1783,14 @@ static struct ast_cli_entry cli_commands[] = {
 
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Endpoints",
                .command = "pjsip list endpoints",
-               .usage = "Usage: pjsip list endpoints\n"
-                                "       List the configured PJSIP endpoints\n"),
+               .usage = "Usage: pjsip list endpoints [ like <pattern> ]\n"
+                               "       List the configured PJSIP endpoints\n"
+                               "       Optional regular expression pattern is used to filter the list.\n"),
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Endpoints",
                .command = "pjsip show endpoints",
-               .usage = "Usage: pjsip show endpoints\n"
-                                "       List(detailed) the configured PJSIP endpoints\n"),
+               .usage = "Usage: pjsip show endpoints [ like <pattern> ]\n"
+                               "       List(detailed) the configured PJSIP endpoints\n"
+                               "       Optional regular expression pattern is used to filter the list.\n"),
        AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Endpoint",
                .command = "pjsip show endpoint",
                .usage = "Usage: pjsip show endpoint <id>\n"
index 5c6e2cc3e8df5387fa52e45e91178d0f8c6ca727..b2377f6ed99ac85599d8d98fd275f4a53adf5f1e 100644 (file)
@@ -298,13 +298,6 @@ struct ast_sip_endpoint_formatter endpoint_identify_formatter = {
        .format_ami = format_ami_endpoint_identify
 };
 
-static int cli_populate_container(void *obj, void *arg, int flags)
-{
-       ao2_link(arg, obj);
-
-       return 0;
-}
-
 static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
 {
        const struct ast_sip_endpoint *endpoint = container;
@@ -328,47 +321,28 @@ static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
        return 0;
 }
 
-static int cli_endpoint_gather_identifies(void *obj, void *arg, int flags)
+static struct ao2_container *cli_get_container(const char *regex)
 {
-       struct ast_sip_endpoint *endpoint = obj;
-       struct ao2_container *container = arg;
-
-       cli_iterator(endpoint, cli_populate_container, container);
-
-       return 0;
-}
+       RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
+       struct ao2_container *s_container;
 
-static struct ao2_container *cli_get_container(void)
-{
-       RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
-       RAII_VAR(struct ao2_container *, s_parent_container, NULL, ao2_cleanup);
-       struct ao2_container *child_container;
-
-       parent_container =  ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "endpoint",
-               AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-       if (!parent_container) {
+       container =  ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "identify", regex);
+       if (!container) {
                return NULL;
        }
 
-       s_parent_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
+       s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
                ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
-       if (!s_parent_container) {
-               return NULL;
-       }
-
-       if (ao2_container_dup(s_parent_container, parent_container, 0)) {
+       if (!s_container) {
                return NULL;
        }
 
-       child_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
-               ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
-       if (!child_container) {
+       if (ao2_container_dup(s_container, container, 0)) {
+               ao2_ref(s_container, -1);
                return NULL;
        }
 
-       ao2_callback(s_parent_container, OBJ_NODATA, cli_endpoint_gather_identifies, child_container);
-
-       return child_container;
+       return s_container;
 }
 
 static void *cli_retrieve_by_id(const char *id)
@@ -461,12 +435,14 @@ static char *my_cli_traverse_objects(struct ast_cli_entry *e, int cmd,
 static struct ast_cli_entry cli_identify[] = {
 AST_CLI_DEFINE(my_cli_traverse_objects, "List PJSIP Identifies",
        .command = "pjsip list identifies",
-       .usage = "Usage: pjsip list identifies\n"
-       "       List the configured PJSIP Identifies\n"),
+       .usage = "Usage: pjsip list identifies [ like <pattern> ]\n"
+       "       List the configured PJSIP Identifies\n"
+       "       Optional regular expression pattern is used to filter the list.\n"),
 AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Identifies",
        .command = "pjsip show identifies",
-       .usage = "Usage: pjsip show identifies\n"
-       "       Show the configured PJSIP Identifies\n"),
+       .usage = "Usage: pjsip show identifies [ like <pattern> ]\n"
+       "       Show the configured PJSIP Identifies\n"
+       "       Optional regular expression pattern is used to filter the list.\n"),
 AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Identify",
        .command = "pjsip show identify",
        .usage = "Usage: pjsip show identify <id>\n"
index b51a48a6714fc54fca07eab6ac0bbec20032b31e..04ff1df607200478846398dbda13e55bd6896720 100644 (file)
@@ -1639,11 +1639,12 @@ static int ami_show_outbound_registrations(struct mansession *s,
        return 0;
 }
 
-static struct ao2_container *cli_get_container(void)
+static struct ao2_container *cli_get_container(const char *regex)
 {
-       RAII_VAR(struct ao2_container *, container, get_registrations(), ao2_cleanup);
+       RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
        struct ao2_container *s_container;
 
+       container = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "registration", regex);
        if (!container) {
                return NULL;
        }
@@ -1747,12 +1748,14 @@ static struct ast_cli_entry cli_outbound_registration[] = {
        AST_CLI_DEFINE(cli_register, "Registers an outbound registration target"),
        AST_CLI_DEFINE(my_cli_traverse_objects, "List PJSIP Registrations",
                .command = "pjsip list registrations",
-               .usage = "Usage: pjsip list registrations\n"
-                                "       List the configured PJSIP Registrations\n"),
+               .usage = "Usage: pjsip list registrations [ like <pattern> ]\n"
+                               "       List the configured PJSIP Registrations\n"
+                               "       Optional regular expression pattern is used to filter the list.\n"),
        AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registrations",
                .command = "pjsip show registrations",
-               .usage = "Usage: pjsip show registrations\n"
-                                "       Show the configured PJSIP Registrations\n"),
+               .usage = "Usage: pjsip show registrations [ like <pattern> ]\n"
+                               "       Show the configured PJSIP Registrations\n"
+                               "       Optional regular expression pattern is used to filter the list.\n"),
        AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Registration",
                .command = "pjsip show registration",
                .usage = "Usage: pjsip show registration <id>\n"