CI: Various updates to buildAsterisk.sh
[asterisk/asterisk.git] / main / pbx_hangup_handler.c
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
55         ast_channel_publish_blob(chan, ast_channel_hangup_handler_type(), blob);
56 }
57
58 int ast_pbx_hangup_handler_run(struct ast_channel *chan)
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          */
74         ast_softhangup_nolock(chan, AST_SOFTHANGUP_HANGUP_EXEC);
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
95 void ast_pbx_hangup_handler_init(struct ast_channel *chan)
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
103 void ast_pbx_hangup_handler_destroy(struct ast_channel *chan)
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
119 int ast_pbx_hangup_handler_pop(struct ast_channel *chan)
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  */
179 static void ast_pbx_hangup_handler_headers(int fd)
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
237         ast_pbx_hangup_handler_headers(a->fd);
238         ast_pbx_hangup_handler_show(a->fd, chan);
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
268         iter = ast_channel_iterator_all_new();
269         if (!iter) {
270                 return CLI_FAILURE;
271         }
272
273         ast_pbx_hangup_handler_headers(a->fd);
274         for (; (chan = ast_channel_iterator_next(iter)); ast_channel_unref(chan)) {
275                 ast_pbx_hangup_handler_show(a->fd, chan);
276         }
277         ast_channel_iterator_destroy(iter);
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 {
289         ast_cli_unregister_multiple(cli, ARRAY_LEN(cli));
290 }
291
292 int load_pbx_hangup_handler(void)
293 {
294         ast_cli_register_multiple(cli, ARRAY_LEN(cli));
295         ast_register_cleanup(unload_pbx_hangup_handler);
296
297         return 0;
298 }