Asterisk - The Open Source Telephony Project  GIT-master-932eae6
pbx_hangup_handler.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2016, CFWare, LLC
5  *
6  * Corey Farrell <git@cfware.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief PBX Hangup Handler management routines.
22  *
23  * \author Corey Farrell <git@cfware.com>
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 #include "asterisk/_private.h"
33 #include "asterisk/app.h"
34 #include "asterisk/cli.h"
35 #include "asterisk/linkedlists.h"
36 #include "asterisk/pbx.h"
38 #include "asterisk/utils.h"
39 
40 /*!
41  * \internal
42  * \brief Publish a hangup handler related message to \ref stasis
43  */
44 static void publish_hangup_handler_message(const char *action, struct ast_channel *chan, const char *handler)
45 {
46  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
47 
48  blob = ast_json_pack("{s: s, s: s}",
49  "type", action,
50  "handler", S_OR(handler, ""));
51  if (!blob) {
52  return;
53  }
54 
56 }
57 
59 {
60  struct ast_hangup_handler_list *handlers;
61  struct ast_hangup_handler *h_handler;
62 
63  ast_channel_lock(chan);
64  handlers = ast_channel_hangup_handlers(chan);
65  if (AST_LIST_EMPTY(handlers)) {
66  ast_channel_unlock(chan);
67  return 0;
68  }
69 
70  /*
71  * Make sure that the channel is marked as hungup since we are
72  * going to run the hangup handlers on it.
73  */
75 
76  for (;;) {
77  handlers = ast_channel_hangup_handlers(chan);
78  h_handler = AST_LIST_REMOVE_HEAD(handlers, node);
79  if (!h_handler) {
80  break;
81  }
82 
83  publish_hangup_handler_message("run", chan, h_handler->args);
84  ast_channel_unlock(chan);
85 
86  ast_app_exec_sub(NULL, chan, h_handler->args, 1);
87  ast_free(h_handler);
88 
89  ast_channel_lock(chan);
90  }
91  ast_channel_unlock(chan);
92  return 1;
93 }
94 
96 {
97  struct ast_hangup_handler_list *handlers;
98 
99  handlers = ast_channel_hangup_handlers(chan);
100  AST_LIST_HEAD_INIT_NOLOCK(handlers);
101 }
102 
104 {
105  struct ast_hangup_handler_list *handlers;
106  struct ast_hangup_handler *h_handler;
107 
108  ast_channel_lock(chan);
109 
110  /* Get rid of each of the hangup handlers on the channel */
111  handlers = ast_channel_hangup_handlers(chan);
112  while ((h_handler = AST_LIST_REMOVE_HEAD(handlers, node))) {
113  ast_free(h_handler);
114  }
115 
116  ast_channel_unlock(chan);
117 }
118 
120 {
121  struct ast_hangup_handler_list *handlers;
122  struct ast_hangup_handler *h_handler;
123 
124  ast_channel_lock(chan);
125  handlers = ast_channel_hangup_handlers(chan);
126  h_handler = AST_LIST_REMOVE_HEAD(handlers, node);
127  if (h_handler) {
128  publish_hangup_handler_message("pop", chan, h_handler->args);
129  }
130  ast_channel_unlock(chan);
131  if (h_handler) {
132  ast_free(h_handler);
133  return 1;
134  }
135  return 0;
136 }
137 
138 void ast_pbx_hangup_handler_push(struct ast_channel *chan, const char *handler)
139 {
140  struct ast_hangup_handler_list *handlers;
141  struct ast_hangup_handler *h_handler;
142  const char *expanded_handler;
143 
144  if (ast_strlen_zero(handler)) {
145  return;
146  }
147 
148  expanded_handler = ast_app_expand_sub_args(chan, handler);
149  if (!expanded_handler) {
150  return;
151  }
152  h_handler = ast_malloc(sizeof(*h_handler) + 1 + strlen(expanded_handler));
153  if (!h_handler) {
154  ast_free((char *) expanded_handler);
155  return;
156  }
157  strcpy(h_handler->args, expanded_handler);/* Safe */
158  ast_free((char *) expanded_handler);
159 
160  ast_channel_lock(chan);
161 
162  handlers = ast_channel_hangup_handlers(chan);
163  AST_LIST_INSERT_HEAD(handlers, h_handler, node);
164  publish_hangup_handler_message("push", chan, h_handler->args);
165  ast_channel_unlock(chan);
166 }
167 
168 #define HANDLER_FORMAT "%-30s %s\n"
169 
170 /*!
171  * \internal
172  * \brief CLI output the hangup handler headers.
173  * \since 11.0
174  *
175  * \param fd CLI file descriptor to use.
176  *
177  * \return Nothing
178  */
180 {
181  ast_cli(fd, HANDLER_FORMAT, "Channel", "Handler");
182 }
183 
184 /*!
185  * \internal
186  * \brief CLI output the channel hangup handlers.
187  * \since 11.0
188  *
189  * \param fd CLI file descriptor to use.
190  * \param chan Channel to show hangup handlers.
191  *
192  * \return Nothing
193  */
194 static void ast_pbx_hangup_handler_show(int fd, struct ast_channel *chan)
195 {
196  struct ast_hangup_handler_list *handlers;
197  struct ast_hangup_handler *h_handler;
198  int first = 1;
199 
200  ast_channel_lock(chan);
201  handlers = ast_channel_hangup_handlers(chan);
202  AST_LIST_TRAVERSE(handlers, h_handler, node) {
203  ast_cli(fd, HANDLER_FORMAT, first ? ast_channel_name(chan) : "", h_handler->args);
204  first = 0;
205  }
206  ast_channel_unlock(chan);
207 }
208 
209 /*
210  * \brief 'show hanguphandlers <channel>' CLI command implementation function...
211  */
212 static char *handle_show_hangup_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
213 {
214  struct ast_channel *chan;
215 
216  switch (cmd) {
217  case CLI_INIT:
218  e->command = "core show hanguphandlers";
219  e->usage =
220  "Usage: core show hanguphandlers <channel>\n"
221  " Show hangup handlers of a specified channel.\n";
222  return NULL;
223  case CLI_GENERATE:
224  return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args);
225  }
226 
227  if (a->argc < 4) {
228  return CLI_SHOWUSAGE;
229  }
230 
231  chan = ast_channel_get_by_name(a->argv[3]);
232  if (!chan) {
233  ast_cli(a->fd, "Channel does not exist.\n");
234  return CLI_FAILURE;
235  }
236 
239 
240  ast_channel_unref(chan);
241 
242  return CLI_SUCCESS;
243 }
244 
245 /*
246  * \brief 'show hanguphandlers all' CLI command implementation function...
247  */
248 static char *handle_show_hangup_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
249 {
250  struct ast_channel_iterator *iter;
251  struct ast_channel *chan;
252 
253  switch (cmd) {
254  case CLI_INIT:
255  e->command = "core show hanguphandlers all";
256  e->usage =
257  "Usage: core show hanguphandlers all\n"
258  " Show hangup handlers for all channels.\n";
259  return NULL;
260  case CLI_GENERATE:
261  return NULL;
262  }
263 
264  if (a->argc < 4) {
265  return CLI_SHOWUSAGE;
266  }
267 
269  if (!iter) {
270  return CLI_FAILURE;
271  }
272 
274  for (; (chan = ast_channel_iterator_next(iter)); ast_channel_unref(chan)) {
276  }
278 
279  return CLI_SUCCESS;
280 }
281 
282 static struct ast_cli_entry cli[] = {
283  AST_CLI_DEFINE(handle_show_hangup_all, "Show hangup handlers of all channels"),
284  AST_CLI_DEFINE(handle_show_hangup_channel, "Show hangup handlers of a specified channel"),
285 };
286 
287 static void unload_pbx_hangup_handler(void)
288 {
290 }
291 
293 {
296 
297  return 0;
298 }
int load_pbx_hangup_handler(void)
#define ast_channel_lock(chan)
Definition: channel.h:2902
static char * handle_show_hangup_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Main Channel structure associated with a channel.
Definition: test_heap.c:38
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
int ast_pbx_hangup_handler_pop(struct ast_channel *chan)
Pop the top of the channel hangup handler stack.
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition: channel.c:1418
Asterisk main include file. File version handling, generic pbx functions.
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
const char * ast_app_expand_sub_args(struct ast_channel *chan, const char *args)
Add missing context/exten to subroutine argument string.
Definition: main/app.c:351
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2938
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
static void publish_hangup_handler_message(const char *action, struct ast_channel *chan, const char *handler)
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
void ast_pbx_hangup_handler_destroy(struct ast_channel *chan)
Destroy the hangup handler container on a channel.
static char * handle_show_hangup_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.h:152
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static void ast_pbx_hangup_handler_headers(int fd)
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
static void unload_pbx_hangup_handler(void)
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
const char * line
Definition: cli.h:162
Utility functions.
int args
This gets set in ast_cli_register()
Definition: cli.h:185
static void ast_pbx_hangup_handler_show(int fd, struct ast_channel *chan)
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:851
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
A set of macros to manage forward-linked lists.
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
#define HANDLER_FORMAT
Core PBX routines and definitions.
const char *const * argv
Definition: cli.h:161
#define CLI_SHOWUSAGE
Definition: cli.h:45
void ast_pbx_hangup_handler_push(struct ast_channel *chan, const char *handler)
Push the given hangup handler onto the channel hangup handler stack.
int ast_pbx_hangup_handler_run(struct ast_channel *chan)
Run all hangup handlers on the channel.
struct sla_ringing_trunk * first
Definition: app_meetme.c:1092
int ast_softhangup_nolock(struct ast_channel *chan, int reason)
Softly hangup up a channel (no channel lock)
Definition: channel.c:2449
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_strlen_zero(a)
Definition: muted.c:73
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
#define ast_channel_unlock(chan)
Definition: channel.h:2903
#define CLI_FAILURE
Definition: cli.h:46
struct stasis_message_type * ast_channel_hangup_handler_type(void)
Message type for hangup handler related actions.
struct ast_hangup_handler_list * ast_channel_hangup_handlers(struct ast_channel *chan)
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
const char * word
Definition: cli.h:163
Prototypes for public functions only of internal interest,.
const char * usage
Definition: cli.h:177
void ast_pbx_hangup_handler_init(struct ast_channel *chan)
Init the hangup handler container on a channel.
#define CLI_SUCCESS
Definition: cli.h:44
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:680
Standard Command Line Interface.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * ast_channel_name(const struct ast_channel *chan)
const int pos
Definition: cli.h:164
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition: channel.c:1356
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59
char * ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Command completion for the list of active channels.
Definition: main/cli.c:1830
int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_args, int ignore_hangup)
Run a subroutine on a channel, placing an optional second channel into autoservice.
Definition: main/app.c:370
static struct ast_cli_entry cli[]
Abstract JSON element (object, array, string, int, ...).
void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message.
struct ast_channel_iterator * ast_channel_iterator_all_new(void)
Create a new channel iterator.
Definition: channel.c:1404
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1450
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
static struct test_val a