Asterisk - The Open Source Telephony Project  21.4.1
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"
37 #include "asterisk/stasis_channels.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 static void ast_pbx_hangup_handler_headers(int fd)
178 {
179  ast_cli(fd, HANDLER_FORMAT, "Channel", "Handler");
180 }
181 
182 /*!
183  * \internal
184  * \brief CLI output the channel hangup handlers.
185  * \since 11.0
186  *
187  * \param fd CLI file descriptor to use.
188  * \param chan Channel to show hangup handlers.
189  */
190 static void ast_pbx_hangup_handler_show(int fd, struct ast_channel *chan)
191 {
192  struct ast_hangup_handler_list *handlers;
193  struct ast_hangup_handler *h_handler;
194  int first = 1;
195 
196  ast_channel_lock(chan);
197  handlers = ast_channel_hangup_handlers(chan);
198  AST_LIST_TRAVERSE(handlers, h_handler, node) {
199  ast_cli(fd, HANDLER_FORMAT, first ? ast_channel_name(chan) : "", h_handler->args);
200  first = 0;
201  }
202  ast_channel_unlock(chan);
203 }
204 
205 /*!
206  * \brief 'show hanguphandlers <channel>' CLI command implementation function...
207  */
208 static char *handle_show_hangup_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
209 {
210  struct ast_channel *chan;
211 
212  switch (cmd) {
213  case CLI_INIT:
214  e->command = "core show hanguphandlers";
215  e->usage =
216  "Usage: core show hanguphandlers <channel>\n"
217  " Show hangup handlers of a specified channel.\n";
218  return NULL;
219  case CLI_GENERATE:
220  return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args);
221  }
222 
223  if (a->argc < 4) {
224  return CLI_SHOWUSAGE;
225  }
226 
227  chan = ast_channel_get_by_name(a->argv[3]);
228  if (!chan) {
229  ast_cli(a->fd, "Channel does not exist.\n");
230  return CLI_FAILURE;
231  }
232 
233  ast_pbx_hangup_handler_headers(a->fd);
234  ast_pbx_hangup_handler_show(a->fd, chan);
235 
236  ast_channel_unref(chan);
237 
238  return CLI_SUCCESS;
239 }
240 
241 /*!
242  * \brief 'show hanguphandlers all' CLI command implementation function...
243  */
244 static char *handle_show_hangup_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
245 {
246  struct ast_channel_iterator *iter;
247  struct ast_channel *chan;
248 
249  switch (cmd) {
250  case CLI_INIT:
251  e->command = "core show hanguphandlers all";
252  e->usage =
253  "Usage: core show hanguphandlers all\n"
254  " Show hangup handlers for all channels.\n";
255  return NULL;
256  case CLI_GENERATE:
257  return NULL;
258  }
259 
260  if (a->argc < 4) {
261  return CLI_SHOWUSAGE;
262  }
263 
265  if (!iter) {
266  return CLI_FAILURE;
267  }
268 
269  ast_pbx_hangup_handler_headers(a->fd);
270  for (; (chan = ast_channel_iterator_next(iter)); ast_channel_unref(chan)) {
271  ast_pbx_hangup_handler_show(a->fd, chan);
272  }
274 
275  return CLI_SUCCESS;
276 }
277 
278 static struct ast_cli_entry cli[] = {
279  AST_CLI_DEFINE(handle_show_hangup_all, "Show hangup handlers of all channels"),
280  AST_CLI_DEFINE(handle_show_hangup_channel, "Show hangup handlers of a specified channel"),
281 };
282 
283 static void unload_pbx_hangup_handler(void)
284 {
285  ast_cli_unregister_multiple(cli, ARRAY_LEN(cli));
286 }
287 
289 {
290  ast_cli_register_multiple(cli, ARRAY_LEN(cli));
291  ast_register_cleanup(unload_pbx_hangup_handler);
292 
293  return 0;
294 }
int load_pbx_hangup_handler(void)
static char * handle_show_hangup_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
'show hanguphandlers ' CLI command implementation function...
Main Channel structure associated with a channel.
Definition: test_heap.c:38
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:1422
Asterisk main include file. File version handling, generic pbx functions.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
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:278
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
descriptor for a cli entry.
Definition: cli.h:171
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)
'show hanguphandlers all' CLI command implementation function...
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
Utility functions.
int args
This gets set in ast_cli_register()
Definition: cli.h:185
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
A set of macros to manage forward-linked lists.
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
Core PBX routines and definitions.
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.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
struct stasis_message_type * ast_channel_hangup_handler_type(void)
Message type for hangup handler related actions.
char * command
Definition: cli.h:186
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 AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
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:80
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition: channel.c:1360
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:1865
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:297
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:1408
int ast_softhangup_nolock(struct ast_channel *chan, int cause)
Softly hangup up a channel (no channel lock)
Definition: channel.c:2458
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
#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:941
Application convenience functions, designed to give consistent look and feel to Asterisk apps...