Thu Sep 7 01:03:00 2017

Asterisk developer's documentation


func_cdr.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999-2006, Digium, Inc.
00005  *
00006  * Portions Copyright (C) 2005, Anthony Minessale II
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief  Call Detail Record related dialplan functions
00022  *
00023  * \author Anthony Minessale II 
00024  *
00025  * \ingroup functions
00026  */
00027 
00028 /*** MODULEINFO
00029    <support_level>core</support_level>
00030  ***/
00031 
00032 #include "asterisk.h"
00033 
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 366048 $")
00035 
00036 #include "asterisk/module.h"
00037 #include "asterisk/channel.h"
00038 #include "asterisk/pbx.h"
00039 #include "asterisk/utils.h"
00040 #include "asterisk/app.h"
00041 #include "asterisk/cdr.h"
00042 
00043 /*** DOCUMENTATION
00044    <function name="CDR" language="en_US">
00045       <synopsis>
00046          Gets or sets a CDR variable.
00047       </synopsis> 
00048       <syntax>
00049          <parameter name="name" required="true">
00050             <para>CDR field name:</para>
00051             <enumlist>
00052                <enum name="clid">
00053                   <para>Caller ID.</para>
00054                </enum>
00055                <enum name="lastdata">
00056                   <para>Last application arguments.</para>
00057                </enum>
00058                <enum name="disposition">
00059                   <para>ANSWERED, NO ANSWER, BUSY, FAILED.</para>
00060                </enum>
00061                <enum name="src">
00062                   <para>Source.</para>
00063                </enum>
00064                <enum name="start">
00065                   <para>Time the call started.</para>
00066                </enum>
00067                <enum name="amaflags">
00068                   <para>DOCUMENTATION, BILL, IGNORE, etc.</para>
00069                </enum>
00070                <enum name="dst">
00071                   <para>Destination.</para>
00072                </enum>
00073                <enum name="answer">
00074                   <para>Time the call was answered.</para>
00075                </enum>
00076                <enum name="accountcode">
00077                   <para>The channel's account code.</para>
00078                </enum>
00079                <enum name="dcontext">
00080                   <para>Destination context.</para>
00081                </enum>
00082                <enum name="end">
00083                   <para>Time the call ended.</para>
00084                </enum>
00085                <enum name="uniqueid">
00086                   <para>The channel's unique id.</para>
00087                </enum>
00088                <enum name="dstchannel">
00089                   <para>Destination channel.</para>
00090                </enum>
00091                <enum name="duration">
00092                   <para>Duration of the call.</para>
00093                </enum>
00094                <enum name="userfield">
00095                   <para>The channel's user specified field.</para>
00096                </enum>
00097                <enum name="lastapp">
00098                   <para>Last application.</para>
00099                </enum>
00100                <enum name="billsec">
00101                   <para>Duration of the call once it was answered.</para>
00102                </enum>
00103                <enum name="channel">
00104                   <para>Channel name.</para>
00105                </enum>
00106                <enum name="sequence">
00107                   <para>CDR sequence number.</para>
00108                </enum>
00109             </enumlist>
00110          </parameter>
00111          <parameter name="options" required="false">
00112             <optionlist>
00113                <option name="f">
00114                   <para>Returns billsec or duration fields as floating point values.</para>
00115                </option>
00116                <option name="l">
00117                   <para>Uses the most recent CDR on a channel with multiple records</para>
00118                </option>
00119                <option name="r">
00120                   <para>Searches the entire stack of CDRs on the channel.</para>
00121                </option>
00122                <option name="s">
00123                   <para>Skips any CDR's that are marked 'LOCKED' due to forkCDR() calls.
00124                   (on setting/writing CDR vars only)</para>
00125                </option>
00126                <option name="u">
00127                   <para>Retrieves the raw, unprocessed value.</para>
00128                   <para>For example, 'start', 'answer', and 'end' will be retrieved as epoch
00129                   values, when the <literal>u</literal> option is passed, but formatted as YYYY-MM-DD HH:MM:SS
00130                   otherwise.  Similarly, disposition and amaflags will return their raw
00131                   integral values.</para>
00132                </option>
00133             </optionlist>
00134          </parameter>
00135       </syntax>
00136       <description>
00137          <para>All of the CDR field names are read-only, except for <literal>accountcode</literal>,
00138          <literal>userfield</literal>, and <literal>amaflags</literal>. You may, however, supply
00139          a name not on the above list, and create your own variable, whose value can be changed
00140          with this function, and this variable will be stored on the cdr.</para>
00141          <note><para>For setting CDR values, the <literal>l</literal> flag does not apply to
00142          setting the <literal>accountcode</literal>, <literal>userfield</literal>, or
00143          <literal>amaflags</literal>.</para><para>CDRs can only be modified before the bridge
00144          between two channels is torn down. For example, CDRs may not be modified after the
00145          <literal>Dial</literal> application has returned.</para></note>
00146          <para>Raw values for <literal>disposition</literal>:</para>
00147          <enumlist>
00148             <enum name="0">
00149                <para>NO ANSWER</para>
00150             </enum>
00151             <enum name="1">
00152                <para>NO ANSWER (NULL record)</para>
00153             </enum>
00154             <enum name="2">
00155                <para>FAILED</para>
00156             </enum>
00157             <enum name="4">
00158                <para>BUSY</para>
00159             </enum>
00160             <enum name="8">
00161                <para>ANSWERED</para>
00162             </enum>
00163          </enumlist>
00164          <para>Raw values for <literal>amaflags</literal>:</para>
00165          <enumlist>
00166             <enum name="1">
00167                <para>OMIT</para>
00168             </enum>
00169             <enum name="2">
00170                <para>BILLING</para>
00171             </enum>
00172             <enum name="3">
00173                <para>DOCUMENTATION</para>
00174             </enum>
00175          </enumlist>
00176          <para>Example: exten => 1,1,Set(CDR(userfield)=test)</para>
00177       </description>
00178    </function>
00179  ***/
00180 
00181 enum cdr_option_flags {
00182    OPT_RECURSIVE = (1 << 0),
00183    OPT_UNPARSED = (1 << 1),
00184    OPT_LAST = (1 << 2),
00185    OPT_SKIPLOCKED = (1 << 3),
00186    OPT_FLOAT = (1 << 4),
00187 };
00188 
00189 AST_APP_OPTIONS(cdr_func_options, {
00190    AST_APP_OPTION('f', OPT_FLOAT),
00191    AST_APP_OPTION('l', OPT_LAST),
00192    AST_APP_OPTION('r', OPT_RECURSIVE),
00193    AST_APP_OPTION('s', OPT_SKIPLOCKED),
00194    AST_APP_OPTION('u', OPT_UNPARSED),
00195 });
00196 
00197 static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
00198           char *buf, size_t len)
00199 {
00200    char *ret = NULL;
00201    struct ast_flags flags = { 0 };
00202    struct ast_cdr *cdr;
00203    AST_DECLARE_APP_ARGS(args,
00204               AST_APP_ARG(variable);
00205               AST_APP_ARG(options);
00206    );
00207 
00208    if (ast_strlen_zero(parse) || !chan)
00209       return -1;
00210 
00211    ast_channel_lock(chan);
00212    cdr = chan->cdr;
00213    if (!cdr) {
00214       ast_channel_unlock(chan);
00215       return -1;
00216    }
00217 
00218    AST_STANDARD_APP_ARGS(args, parse);
00219 
00220    if (!ast_strlen_zero(args.options))
00221       ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
00222 
00223    if (ast_test_flag(&flags, OPT_LAST))
00224       while (cdr->next)
00225          cdr = cdr->next;
00226 
00227    if (ast_test_flag(&flags, OPT_SKIPLOCKED))
00228       while (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED) && cdr->next)
00229          cdr = cdr->next;
00230 
00231    if (!strcasecmp("billsec", args.variable) && ast_test_flag(&flags, OPT_FLOAT)) {
00232       if (!ast_tvzero(cdr->answer)) {
00233          double hrtime;
00234 
00235          if(!ast_tvzero(cdr->end))
00236             hrtime = (double)(ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0);
00237          else
00238             hrtime = (double)(ast_tvdiff_us(ast_tvnow(), cdr->answer) / 1000000.0);
00239 
00240          snprintf(buf, len, "%lf", hrtime);
00241       } else {
00242          snprintf(buf, len, "%lf", 0.0);
00243       }
00244       ret = buf;
00245    } else if (!strcasecmp("duration", args.variable) && ast_test_flag(&flags, OPT_FLOAT)) {
00246          double hrtime;
00247 
00248          if(!ast_tvzero(cdr->end))
00249             hrtime = (double)(ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0);
00250          else
00251             hrtime = (double)(ast_tvdiff_us(ast_tvnow(), cdr->start) / 1000000.0);
00252 
00253          snprintf(buf, len, "%lf", hrtime);
00254 
00255       if (!ast_strlen_zero(buf)) {
00256          ret = buf;
00257       }
00258    } else {
00259       ast_cdr_getvar(cdr, args.variable, &ret, buf, len,
00260                 ast_test_flag(&flags, OPT_RECURSIVE),
00261                ast_test_flag(&flags, OPT_UNPARSED));
00262    }
00263 
00264    ast_channel_unlock(chan);
00265    return ret ? 0 : -1;
00266 }
00267 
00268 static int cdr_write(struct ast_channel *chan, const char *cmd, char *parse,
00269            const char *value)
00270 {
00271    struct ast_cdr *cdr;
00272    struct ast_flags flags = { 0 };
00273    AST_DECLARE_APP_ARGS(args,
00274               AST_APP_ARG(variable);
00275               AST_APP_ARG(options);
00276    );
00277 
00278    if (ast_strlen_zero(parse) || !value || !chan)
00279       return -1;
00280 
00281    ast_channel_lock(chan);
00282    cdr = chan->cdr;
00283    if (!cdr) {
00284       ast_channel_unlock(chan);
00285       return -1;
00286    }
00287 
00288    AST_STANDARD_APP_ARGS(args, parse);
00289 
00290    if (!ast_strlen_zero(args.options))
00291       ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
00292 
00293    if (ast_test_flag(&flags, OPT_LAST))
00294       while (cdr->next)
00295          cdr = cdr->next;
00296 
00297    if (!strcasecmp(args.variable, "accountcode"))  /* the 'l' flag doesn't apply to setting the accountcode, userfield, or amaflags */
00298       ast_cdr_setaccount(chan, value);
00299    else if (!strcasecmp(args.variable, "peeraccount"))
00300       ast_cdr_setpeeraccount(chan, value);
00301    else if (!strcasecmp(args.variable, "userfield"))
00302       ast_cdr_setuserfield(chan, value);
00303    else if (!strcasecmp(args.variable, "amaflags"))
00304       ast_cdr_setamaflags(chan, value);
00305    else
00306       ast_cdr_setvar(cdr, args.variable, value, ast_test_flag(&flags, OPT_RECURSIVE));
00307       /* No need to worry about the u flag, as all fields for which setting
00308        * 'u' would do anything are marked as readonly. */
00309 
00310    ast_channel_unlock(chan);
00311    return 0;
00312 }
00313 
00314 static struct ast_custom_function cdr_function = {
00315    .name = "CDR",
00316    .read = cdr_read,
00317    .write = cdr_write,
00318 };
00319 
00320 static int unload_module(void)
00321 {
00322    return ast_custom_function_unregister(&cdr_function);
00323 }
00324 
00325 static int load_module(void)
00326 {
00327    return ast_custom_function_register(&cdr_function);
00328 }
00329 
00330 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Detail Record (CDR) dialplan function");

Generated on 7 Sep 2017 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1