Fixup skinny registration following network issues.
[asterisk/asterisk.git] / funcs / func_cdr.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999-2006, Digium, Inc.
5  *
6  * Portions Copyright (C) 2005, Anthony Minessale II
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  Call Detail Record related dialplan functions
22  *
23  * \author Anthony Minessale II
24  *
25  * \ingroup functions
26  */
27
28 /*** MODULEINFO
29         <support_level>core</support_level>
30  ***/
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include "asterisk/module.h"
37 #include "asterisk/channel.h"
38 #include "asterisk/pbx.h"
39 #include "asterisk/utils.h"
40 #include "asterisk/app.h"
41 #include "asterisk/cdr.h"
42
43 /*** DOCUMENTATION
44         <function name="CDR" language="en_US">
45                 <synopsis>
46                         Gets or sets a CDR variable.
47                 </synopsis>
48                 <syntax>
49                         <parameter name="name" required="true">
50                                 <para>CDR field name:</para>
51                                 <enumlist>
52                                         <enum name="clid">
53                                                 <para>Caller ID.</para>
54                                         </enum>
55                                         <enum name="lastdata">
56                                                 <para>Last application arguments.</para>
57                                         </enum>
58                                         <enum name="disposition">
59                                                 <para>The final state of the CDR.</para>
60                                                 <enumlist>
61                                                         <enum name="0">
62                                                                 <para><literal>NO ANSWER</literal></para>
63                                                         </enum>
64                                                         <enum name="1">
65                                                                 <para><literal>NO ANSWER</literal> (NULL record)</para>
66                                                         </enum>
67                                                         <enum name="2">
68                                                                 <para><literal>FAILED</literal></para>
69                                                         </enum>
70                                                         <enum name="4">
71                                                                 <para><literal>BUSY</literal></para>
72                                                         </enum>
73                                                         <enum name="8">
74                                                                 <para><literal>ANSWERED</literal></para>
75                                                         </enum>
76                                                         <enum name="16">
77                                                                 <para><literal>CONGESTION</literal></para>
78                                                         </enum>
79                                                 </enumlist>
80                                         </enum>
81                                         <enum name="src">
82                                                 <para>Source.</para>
83                                         </enum>
84                                         <enum name="start">
85                                                 <para>Time the call started.</para>
86                                         </enum>
87                                         <enum name="amaflags">
88                                                 <para>R/W the Automatic Message Accounting (AMA) flags on the channel.
89                                                 When read from a channel, the integer value will always be returned.
90                                                 When written to a channel, both the string format or integer value
91                                                 is accepted.</para>
92                                                 <enumlist>
93                                                         <enum name="1"><para><literal>OMIT</literal></para></enum>
94                                                         <enum name="2"><para><literal>BILLING</literal></para></enum>
95                                                         <enum name="3"><para><literal>DOCUMENTATION</literal></para></enum>
96                                                 </enumlist>
97                                                 <warning><para>Accessing this setting is deprecated in CDR. Please use the CHANNEL function instead.</para></warning>
98                                         </enum>
99                                         <enum name="dst">
100                                                 <para>Destination.</para>
101                                         </enum>
102                                         <enum name="answer">
103                                                 <para>Time the call was answered.</para>
104                                         </enum>
105                                         <enum name="accountcode">
106                                                 <para>The channel's account code.</para>
107                                                 <warning><para>Accessing this setting is deprecated in CDR. Please use the CHANNEL function instead.</para></warning>
108                                         </enum>
109                                         <enum name="dcontext">
110                                                 <para>Destination context.</para>
111                                         </enum>
112                                         <enum name="end">
113                                                 <para>Time the call ended.</para>
114                                         </enum>
115                                         <enum name="uniqueid">
116                                                 <para>The channel's unique id.</para>
117                                         </enum>
118                                         <enum name="dstchannel">
119                                                 <para>Destination channel.</para>
120                                         </enum>
121                                         <enum name="duration">
122                                                 <para>Duration of the call.</para>
123                                         </enum>
124                                         <enum name="userfield">
125                                                 <para>The channel's user specified field.</para>
126                                         </enum>
127                                         <enum name="lastapp">
128                                                 <para>Last application.</para>
129                                         </enum>
130                                         <enum name="billsec">
131                                                 <para>Duration of the call once it was answered.</para>
132                                         </enum>
133                                         <enum name="channel">
134                                                 <para>Channel name.</para>
135                                         </enum>
136                                         <enum name="sequence">
137                                                 <para>CDR sequence number.</para>
138                                         </enum>
139                                 </enumlist>
140                         </parameter>
141                         <parameter name="options" required="false">
142                                 <optionlist>
143                                         <option name="f">
144                                                 <para>Returns billsec or duration fields as floating point values.</para>
145                                         </option>
146                                         <option name="u">
147                                                 <para>Retrieves the raw, unprocessed value.</para>
148                                                 <para>For example, 'start', 'answer', and 'end' will be retrieved as epoch
149                                                 values, when the <literal>u</literal> option is passed, but formatted as YYYY-MM-DD HH:MM:SS
150                                                 otherwise.  Similarly, disposition and amaflags will return their raw
151                                                 integral values.</para>
152                                         </option>
153                                 </optionlist>
154                         </parameter>
155                 </syntax>
156                 <description>
157                         <para>All of the CDR field names are read-only, except for <literal>accountcode</literal>,
158                         <literal>userfield</literal>, and <literal>amaflags</literal>. You may, however, supply
159                         a name not on the above list, and create your own variable, whose value can be changed
160                         with this function, and this variable will be stored on the CDR.</para>
161                         <note><para>CDRs can only be modified before the bridge between two channels is
162                         torn down. For example, CDRs may not be modified after the <literal>Dial</literal>
163                         application has returned.</para></note>
164                         <para>Example: exten => 1,1,Set(CDR(userfield)=test)</para>
165                 </description>
166         </function>
167         <function name="CDR_PROP" language="en_US">
168                 <synopsis>
169                         Set a property on a channel's CDR.
170                 </synopsis>
171                 <syntax>
172                         <parameter name="name" required="true">
173                                 <para>The property to set on the CDR.</para>
174                                 <enumlist>
175                                         <enum name="party_a">
176                                                 <para>Set this channel as the preferred Party A when
177                                                 channels are associated together.</para>
178                                                 <para>Write-Only</para>
179                                         </enum>
180                                         <enum name="disable">
181                                                 <para>Disable CDRs for this channel.</para>
182                                                 <para>Write-Only</para>
183                                         </enum>
184                                 </enumlist>
185                         </parameter>
186                 </syntax>
187                 <description>
188                         <para>This function sets a property on a channel's CDR. Properties
189                         alter the behavior of how the CDR operates for that channel.</para>
190                 </description>
191         </function>
192  ***/
193
194 enum cdr_option_flags {
195         OPT_UNPARSED = (1 << 1),
196         OPT_FLOAT = (1 << 2),
197 };
198
199 AST_APP_OPTIONS(cdr_func_options, {
200         AST_APP_OPTION('f', OPT_FLOAT),
201         AST_APP_OPTION('u', OPT_UNPARSED),
202 });
203
204 static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
205                     char *buf, size_t len)
206 {
207         char *value = NULL;
208         struct ast_flags flags = { 0 };
209         char tempbuf[512];
210         char *info;
211         AST_DECLARE_APP_ARGS(args,
212                 AST_APP_ARG(variable);
213                 AST_APP_ARG(options);
214         );
215
216         buf[0] = '\0';/* Ensure the buffer is initialized. */
217
218         if (!chan) {
219                 return -1;
220         }
221
222         if (ast_strlen_zero(parse)) {
223                 ast_log(AST_LOG_WARNING, "FUNC_CDR requires a variable (FUNC_CDR(variable[,option]))\n)");
224                 return -1;
225         }
226         info = ast_strdupa(parse);
227         AST_STANDARD_APP_ARGS(args, info);
228
229         if (!ast_strlen_zero(args.options)) {
230                 ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
231         }
232
233         if (ast_strlen_zero(ast_channel_name(chan))) {
234                 /* Format request on a dummy channel */
235                 ast_cdr_format_var(ast_channel_cdr(chan), args.variable, &value, tempbuf, sizeof(tempbuf), 0);
236                 if (ast_strlen_zero(value)) {
237                         return 0;
238                 }
239                 ast_copy_string(tempbuf, value, sizeof(tempbuf));
240                 ast_set_flag(&flags, OPT_UNPARSED);
241         } else if (ast_cdr_getvar(ast_channel_name(chan), args.variable, tempbuf, sizeof(tempbuf))) {
242                 return 0;
243         }
244
245         if (ast_test_flag(&flags, OPT_FLOAT)
246                 && (!strcasecmp("billsec", args.variable) || !strcasecmp("duration", args.variable))) {
247                 long ms;
248                 double dtime;
249
250                 if (sscanf(tempbuf, "%30ld", &ms) != 1) {
251                         ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
252                                 args.variable, tempbuf, ast_channel_name(chan));
253                         return 0;
254                 }
255                 dtime = (double)(ms / 1000.0);
256                 snprintf(tempbuf, sizeof(tempbuf), "%lf", dtime);
257         } else if (!ast_test_flag(&flags, OPT_UNPARSED)) {
258                 if (!strcasecmp("start", args.variable)
259                         || !strcasecmp("end", args.variable)
260                         || !strcasecmp("answer", args.variable)) {
261                         struct timeval fmt_time;
262                         struct ast_tm tm;
263                         /* tv_usec is suseconds_t, which could be int or long */
264                         long int tv_usec;
265
266                         if (sscanf(tempbuf, "%ld.%ld", &fmt_time.tv_sec, &tv_usec) != 2) {
267                                 ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
268                                         args.variable, tempbuf, ast_channel_name(chan));
269                                 return 0;
270                         }
271                         fmt_time.tv_usec = tv_usec;
272                         ast_localtime(&fmt_time, &tm, NULL);
273                         ast_strftime(tempbuf, sizeof(*tempbuf), "%Y-%m-%d %T", &tm);
274                 } else if (!strcasecmp("disposition", args.variable)) {
275                         int disposition;
276
277                         if (sscanf(tempbuf, "%8d", &disposition) != 1) {
278                                 ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
279                                         args.variable, tempbuf, ast_channel_name(chan));
280                                 return 0;
281                         }
282                         snprintf(tempbuf, sizeof(tempbuf), "%s", ast_cdr_disp2str(disposition));
283                 } else if (!strcasecmp("amaflags", args.variable)) {
284                         int amaflags;
285
286                         if (sscanf(tempbuf, "%8d", &amaflags) != 1) {
287                                 ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
288                                         args.variable, tempbuf, ast_channel_name(chan));
289                                 return 0;
290                         }
291                         snprintf(tempbuf, sizeof(tempbuf), "%s", ast_channel_amaflags2string(amaflags));
292                 }
293         }
294
295         ast_copy_string(buf, tempbuf, len);
296         return 0;
297 }
298
299 static int cdr_write(struct ast_channel *chan, const char *cmd, char *parse,
300                      const char *value)
301 {
302         struct ast_flags flags = { 0 };
303         AST_DECLARE_APP_ARGS(args,
304                 AST_APP_ARG(variable);
305                 AST_APP_ARG(options);
306         );
307
308         if (ast_strlen_zero(parse) || !value || !chan) {
309                 return -1;
310         }
311
312         AST_STANDARD_APP_ARGS(args, parse);
313
314         if (!ast_strlen_zero(args.options)) {
315                 ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
316         }
317
318         if (!strcasecmp(args.variable, "accountcode")) {
319                 ast_log(AST_LOG_WARNING, "Using the CDR function to set 'accountcode' is deprecated. Please use the CHANNEL function instead.\n");
320                 ast_channel_lock(chan);
321                 ast_channel_accountcode_set(chan, value);
322                 ast_channel_unlock(chan);
323         } else if (!strcasecmp(args.variable, "peeraccount")) {
324                 ast_log(AST_LOG_WARNING, "The 'peeraccount' setting is not supported. Please set the 'accountcode' on the appropriate channel using the CHANNEL function.\n");
325         } else if (!strcasecmp(args.variable, "userfield")) {
326                 ast_cdr_setuserfield(ast_channel_name(chan), value);
327         } else if (!strcasecmp(args.variable, "amaflags")) {
328                 ast_log(AST_LOG_WARNING, "Using the CDR function to set 'amaflags' is deprecated. Please use the CHANNEL function instead.\n");
329                 if (isdigit(*value)) {
330                         int amaflags;
331                         sscanf(value, "%30d", &amaflags);
332                         ast_channel_lock(chan);
333                         ast_channel_amaflags_set(chan, amaflags);
334                         ast_channel_unlock(chan);
335                 } else {
336                         ast_channel_lock(chan);
337                         ast_channel_amaflags_set(chan, ast_channel_string2amaflag(value));
338                         ast_channel_unlock(chan);
339                 }
340         } else {
341                 ast_cdr_setvar(ast_channel_name(chan), args.variable, value);
342         }
343
344         return 0;
345 }
346
347 static int cdr_prop_write(struct ast_channel *chan, const char *cmd, char *parse,
348                      const char *value)
349 {
350         enum ast_cdr_options option;
351
352         AST_DECLARE_APP_ARGS(args,
353                 AST_APP_ARG(variable);
354                 AST_APP_ARG(options);
355         );
356
357         if (ast_strlen_zero(parse) || !value || !chan) {
358                 return -1;
359         }
360
361         AST_STANDARD_APP_ARGS(args, parse);
362
363         if (!strcasecmp("party_a", args.variable)) {
364                 option = AST_CDR_FLAG_PARTY_A;
365         } else if (!strcasecmp("disable", args.variable)) {
366                 option = AST_CDR_FLAG_DISABLE_ALL;
367         } else {
368                 ast_log(AST_LOG_WARNING, "Unknown option %s used with CDR_PROP\n", args.variable);
369                 return 0;
370         }
371
372         if (ast_true(value)) {
373                 ast_cdr_set_property(ast_channel_name(chan), option);
374         } else {
375                 ast_cdr_clear_property(ast_channel_name(chan), option);
376         }
377         return 0;
378 }
379
380 static struct ast_custom_function cdr_function = {
381         .name = "CDR",
382         .read = cdr_read,
383         .write = cdr_write,
384 };
385
386 static struct ast_custom_function cdr_prop_function = {
387         .name = "CDR_PROP",
388         .read = NULL,
389         .write = cdr_prop_write,
390 };
391
392 static int unload_module(void)
393 {
394         int res = 0;
395
396         res |= ast_custom_function_unregister(&cdr_function);
397         res |= ast_custom_function_unregister(&cdr_prop_function);
398
399         return res;
400 }
401
402 static int load_module(void)
403 {
404         int res = 0;
405
406         res |= ast_custom_function_register(&cdr_function);
407         res |= ast_custom_function_register(&cdr_prop_function);
408
409         return res;
410 }
411
412 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Detail Record (CDR) dialplan functions");