Sun Oct 16 2011 08:41:40

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: 328209 $")
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></note>
00144          <para>Raw values for <literal>disposition</literal>:</para>
00145          <enumlist>
00146             <enum name="0">
00147                <para>NO ANSWER</para>
00148             </enum>
00149             <enum name="1">
00150                <para>NO ANSWER (NULL record)</para>
00151             </enum>
00152             <enum name="2">
00153                <para>FAILED</para>
00154             </enum>
00155             <enum name="4">
00156                <para>BUSY</para>
00157             </enum>
00158             <enum name="8">
00159                <para>ANSWERED</para>
00160             </enum>
00161          </enumlist>
00162          <para>Raw values for <literal>amaflags</literal>:</para>
00163          <enumlist>
00164             <enum name="1">
00165                <para>OMIT</para>
00166             </enum>
00167             <enum name="2">
00168                <para>BILLING</para>
00169             </enum>
00170             <enum name="3">
00171                <para>DOCUMENTATION</para>
00172             </enum>
00173          </enumlist>
00174          <para>Example: exten => 1,1,Set(CDR(userfield)=test)</para>
00175       </description>
00176    </function>
00177  ***/
00178 
00179 enum cdr_option_flags {
00180    OPT_RECURSIVE = (1 << 0),
00181    OPT_UNPARSED = (1 << 1),
00182    OPT_LAST = (1 << 2),
00183    OPT_SKIPLOCKED = (1 << 3),
00184    OPT_FLOAT = (1 << 4),
00185 };
00186 
00187 AST_APP_OPTIONS(cdr_func_options, {
00188    AST_APP_OPTION('f', OPT_FLOAT),
00189    AST_APP_OPTION('l', OPT_LAST),
00190    AST_APP_OPTION('r', OPT_RECURSIVE),
00191    AST_APP_OPTION('s', OPT_SKIPLOCKED),
00192    AST_APP_OPTION('u', OPT_UNPARSED),
00193 });
00194 
00195 static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
00196           char *buf, size_t len)
00197 {
00198    char *ret;
00199    struct ast_flags flags = { 0 };
00200    struct ast_cdr *cdr = chan ? chan->cdr : NULL;
00201    AST_DECLARE_APP_ARGS(args,
00202               AST_APP_ARG(variable);
00203               AST_APP_ARG(options);
00204    );
00205 
00206    if (ast_strlen_zero(parse))
00207       return -1;
00208 
00209    if (!cdr)
00210       return -1;
00211 
00212    AST_STANDARD_APP_ARGS(args, parse);
00213 
00214    if (!ast_strlen_zero(args.options))
00215       ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
00216 
00217    if (ast_test_flag(&flags, OPT_LAST))
00218       while (cdr->next)
00219          cdr = cdr->next;
00220 
00221    if (ast_test_flag(&flags, OPT_SKIPLOCKED))
00222       while (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED) && cdr->next)
00223          cdr = cdr->next;
00224 
00225    if (!strcasecmp("billsec", args.variable) && ast_test_flag(&flags, OPT_FLOAT)) {
00226       if (!ast_tvzero(cdr->answer)) {
00227          double hrtime;
00228 
00229          if(!ast_tvzero(cdr->end))
00230             hrtime = (double)(ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0);
00231          else
00232             hrtime = (double)(ast_tvdiff_us(ast_tvnow(), cdr->answer) / 1000000.0);
00233 
00234          snprintf(buf, len, "%lf", hrtime);
00235       } else {
00236          snprintf(buf, len, "%lf", 0.0);
00237       }
00238       ret = buf;
00239    } else if (!strcasecmp("duration", args.variable) && ast_test_flag(&flags, OPT_FLOAT)) {
00240          double hrtime;
00241 
00242          if(!ast_tvzero(cdr->end))
00243             hrtime = (double)(ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0);
00244          else
00245             hrtime = (double)(ast_tvdiff_us(ast_tvnow(), cdr->start) / 1000000.0);
00246 
00247          snprintf(buf, len, "%lf", hrtime);
00248 
00249       if (!ast_strlen_zero(buf)) {
00250          ret = buf;
00251       }
00252    } else {
00253       ast_cdr_getvar(cdr, args.variable, &ret, buf, len,
00254                 ast_test_flag(&flags, OPT_RECURSIVE),
00255                ast_test_flag(&flags, OPT_UNPARSED));
00256    }
00257 
00258    return ret ? 0 : -1;
00259 }
00260 
00261 static int cdr_write(struct ast_channel *chan, const char *cmd, char *parse,
00262            const char *value)
00263 {
00264    struct ast_cdr *cdr = chan ? chan->cdr : NULL;
00265    struct ast_flags flags = { 0 };
00266    AST_DECLARE_APP_ARGS(args,
00267               AST_APP_ARG(variable);
00268               AST_APP_ARG(options);
00269    );
00270 
00271    if (ast_strlen_zero(parse) || !value || !chan)
00272       return -1;
00273 
00274    if (!cdr)
00275       return -1;
00276 
00277    AST_STANDARD_APP_ARGS(args, parse);
00278 
00279    if (!ast_strlen_zero(args.options))
00280       ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
00281 
00282    if (ast_test_flag(&flags, OPT_LAST))
00283       while (cdr->next)
00284          cdr = cdr->next;
00285 
00286    if (!strcasecmp(args.variable, "accountcode"))  /* the 'l' flag doesn't apply to setting the accountcode, userfield, or amaflags */
00287       ast_cdr_setaccount(chan, value);
00288    else if (!strcasecmp(args.variable, "peeraccount"))
00289       ast_cdr_setpeeraccount(chan, value);
00290    else if (!strcasecmp(args.variable, "userfield"))
00291       ast_cdr_setuserfield(chan, value);
00292    else if (!strcasecmp(args.variable, "amaflags"))
00293       ast_cdr_setamaflags(chan, value);
00294    else
00295       ast_cdr_setvar(cdr, args.variable, value, ast_test_flag(&flags, OPT_RECURSIVE));
00296       /* No need to worry about the u flag, as all fields for which setting
00297        * 'u' would do anything are marked as readonly. */
00298 
00299    return 0;
00300 }
00301 
00302 static struct ast_custom_function cdr_function = {
00303    .name = "CDR",
00304    .read = cdr_read,
00305    .write = cdr_write,
00306 };
00307 
00308 static int unload_module(void)
00309 {
00310    return ast_custom_function_unregister(&cdr_function);
00311 }
00312 
00313 static int load_module(void)
00314 {
00315    return ast_custom_function_register(&cdr_function);
00316 }
00317 
00318 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Detail Record (CDR) dialplan function");