Add channel locking for channel snapshot creation.
[asterisk/asterisk.git] / funcs / func_hangupcause.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999-2012, Digium, Inc.
5  *
6  * Kinsey Moore <kmoore@digium.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 Functions related to retreiving per-channel hangupcause information
22  *
23  * \author Kinsey Moore <kmoore@digium.com>
24  * \ingroup functions
25  *
26  * See Also:
27  * \arg \ref AstCREDITS
28  */
29
30 /*** MODULEINFO
31         <support_level>core</support_level>
32  ***/
33
34 #include "asterisk.h"
35
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37
38 #include "asterisk/module.h"
39 #include "asterisk/channel.h"
40 #include "asterisk/pbx.h"
41 #include "asterisk/utils.h"
42 #include "asterisk/app.h"
43
44 /*** DOCUMENTATION
45         <function name="HANGUPCAUSE" language="en_US">
46                 <synopsis>
47                         Gets per-channel hangupcause information from the channel.
48                 </synopsis>
49                 <syntax>
50                         <parameter name="channel" required="true">
51                                 <para>The name of the channel for which to retreive cause information.</para>
52                         </parameter>
53                         <parameter name="type" required="true">
54                                 <para>Parameter describing which type of information is requested. Types are:</para>
55                                 <enumlist>
56                                         <enum name="tech"><para>Technology-specific cause information</para></enum>
57                                         <enum name="ast"><para>Translated Asterisk cause code</para></enum>
58                                 </enumlist>
59                         </parameter>
60                 </syntax>
61                 <description>
62                         <para>Gets technology-specific or translated Asterisk cause code information
63                         from the channel for the specified channel that resulted from a dial.</para>
64                 </description>
65                 <see-also>
66                         <ref type="function">HANGUPCAUSE_KEYS</ref>
67                         <ref type="application">HangupCauseClear</ref>
68                 </see-also>
69         </function>
70         <function name="HANGUPCAUSE_KEYS" language="en_US">
71                 <synopsis>
72                         Gets the list of channels for which hangup causes are available.
73                 </synopsis>
74                 <description>
75                         <para>Returns a comma-separated list of channel names to be used with the HANGUPCAUSE function.</para>
76                 </description>
77                 <see-also>
78                         <ref type="function">HANGUPCAUSE</ref>
79                         <ref type="application">HangupCauseClear</ref>
80                 </see-also>
81         </function>
82         <application name="HangupCauseClear" language="en_US">
83                 <synopsis>
84                         Clears hangup cause information from the channel that is available through HANGUPCAUSE.
85                 </synopsis>
86                 <description>
87                         <para>Clears all channel-specific hangup cause information from the channel.
88                         This is never done automatically (i.e. for new Dial()s).</para>
89                 </description>
90                 <see-also>
91                         <ref type="function">HANGUPCAUSE</ref>
92                         <ref type="function">HANGUPCAUSE_KEYS</ref>
93                 </see-also>
94         </application>
95  ***/
96
97 /*!
98  * \internal
99  * \brief Read values from the hangupcause ao2 container.
100  *
101  * \param chan Asterisk channel to read
102  * \param cmd Not used
103  * \param data HANGUPCAUSE function argument string
104  * \param buf Buffer to fill with read value.
105  * \param len Length of the buffer
106  *
107  * \retval 0 on success.
108  * \retval -1 on error.
109  */
110 static int hangupcause_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
111 {
112         char *parms;
113         struct ast_control_pvt_cause_code *cause_code;
114         int res = 0;
115         AST_DECLARE_APP_ARGS(args,
116                 AST_APP_ARG(channel);   /*!< Channel name */
117                 AST_APP_ARG(type);      /*!< Type of information requested (ast or tech) */
118                 );
119
120         /* Ensure that the buffer is empty */
121         *buf = 0;
122
123         if (!chan) {
124                 return -1;
125         }
126
127         parms = ast_strdupa(data);
128         AST_STANDARD_APP_ARGS(args, parms);
129         if (args.argc != 2) {
130                 /* Must have two arguments. */
131                 ast_log(LOG_WARNING, "The HANGUPCAUSE function must have 2 parameters, not %d\n", args.argc);
132                 return -1;
133         }
134
135         ast_channel_lock(chan);
136         cause_code = ast_channel_dialed_causes_find(chan, args.channel);
137         ast_channel_unlock(chan);
138
139         if (!cause_code) {
140                 ast_log(LOG_WARNING, "Unable to find information for channel %s\n", args.channel);
141                 return -1;
142         }
143
144         if (!strcmp(args.type, "ast")) {
145                 ast_copy_string(buf, ast_cause2str(cause_code->ast_cause), len);
146         } else if (!strcmp(args.type, "tech")) {
147                 ast_copy_string(buf, cause_code->code, len);
148         } else {
149                 ast_log(LOG_WARNING, "Information type not recognized (%s)\n", args.type);
150                 res = -1;
151         }
152
153         ao2_ref(cause_code, -1);
154
155         return res;
156 }
157
158 /*!
159  * \internal
160  * \brief Read keys from the hangupcause ao2 container.
161  *
162  * \param chan Asterisk channel to read
163  * \param cmd Not used
164  * \param data HANGUPCAUSE_KEYS function argument string
165  * \param buf Buffer to fill with read value.
166  * \param len Length of the buffer
167  *
168  * \retval 0 on success.
169  * \retval -1 on error.
170  */
171 static int hangupcause_keys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
172 {
173         struct ast_str *chanlist;
174
175         /* Ensure that the buffer is empty */
176         *buf = 0;
177
178         if (!chan) {
179                 return -1;
180         }
181
182         ast_channel_lock(chan);
183         chanlist = ast_channel_dialed_causes_channels(chan);
184         ast_channel_unlock(chan);
185
186         if (chanlist && ast_str_strlen(chanlist)) {
187                 ast_copy_string(buf, ast_str_buffer(chanlist), len);
188         }
189
190         ast_free(chanlist);
191         return 0;
192 }
193
194 /*!
195  * \internal
196  * \brief Remove all keys from the hangupcause ao2 container.
197  *
198  * \param chan Asterisk channel to read
199  * \param data Not used
200  *
201  * \retval 0 on success.
202  * \retval -1 on error.
203  */
204 static int hangupcause_clear_exec(struct ast_channel *chan, const char *data) {
205         ast_channel_lock(chan);
206         ast_channel_dialed_causes_clear(chan);
207         ast_channel_unlock(chan);
208         return 0;
209 }
210
211 static struct ast_custom_function hangupcause_function = {
212         .name = "HANGUPCAUSE",
213         .read = hangupcause_read,
214 };
215
216 static struct ast_custom_function hangupcause_keys_function = {
217         .name = "HANGUPCAUSE_KEYS",
218         .read = hangupcause_keys_read,
219 };
220
221 static const char app[] = "HangupCauseClear";
222
223 /*!
224  * \internal
225  * \brief Unload the function module
226  *
227  * \retval 0 on success.
228  * \retval -1 on error.
229  */
230 static int unload_module(void)
231 {
232         int res;
233
234         res = ast_custom_function_unregister(&hangupcause_function);
235         res |= ast_custom_function_unregister(&hangupcause_keys_function);
236         res |= ast_unregister_application(app);
237         return res;
238 }
239
240 /*!
241  * \internal
242  * \brief Load and initialize the function module.
243  *
244  * \retval AST_MODULE_LOAD_SUCCESS on success.
245  * \retval AST_MODULE_LOAD_DECLINE on error.
246  */
247 static int load_module(void)
248 {
249         int res;
250
251         res = ast_custom_function_register(&hangupcause_function);
252         res |= ast_custom_function_register(&hangupcause_keys_function);
253         res |= ast_register_application_xml(app, hangupcause_clear_exec);
254         return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
255 }
256
257 /* Do not wrap the following line. */
258 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "HANGUPCAUSE related functions and applications");