Sat Mar 10 01:54:18 2012

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: 348362 $")
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;
00201    AST_DECLARE_APP_ARGS(args,
00202               AST_APP_ARG(variable);
00203               AST_APP_ARG(options);
00204    );
00205 
00206    if (ast_strlen_zero(parse) || !chan)
00207       return -1;
00208 
00209    ast_channel_lock(chan);
00210    cdr = chan->cdr;
00211    if (!cdr) {
00212       ast_channel_unlock(chan);
00213       return -1;
00214    }
00215 
00216    AST_STANDARD_APP_ARGS(args, parse);
00217 
00218    if (!ast_strlen_zero(args.options))
00219       ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
00220 
00221    if (ast_test_flag(&flags, OPT_LAST))
00222       while (cdr->next)
00223          cdr = cdr->next;
00224 
00225    if (ast_test_flag(&flags, OPT_SKIPLOCKED))
00226       while (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED) && cdr->next)
00227          cdr = cdr->next;
00228 
00229    if (!strcasecmp("billsec", args.variable) && ast_test_flag(&flags, OPT_FLOAT)) {
00230       if (!ast_tvzero(cdr->answer)) {
00231          double hrtime;
00232 
00233          if(!ast_tvzero(cdr->end))
00234             hrtime = (double)(ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0);
00235          else
00236             hrtime = (double)(ast_tvdiff_us(ast_tvnow(), cdr->answer) / 1000000.0);
00237 
00238          snprintf(buf, len, "%lf", hrtime);
00239       } else {
00240          snprintf(buf, len, "%lf", 0.0);
00241       }
00242       ret = buf;
00243    } else if (!strcasecmp("duration", args.variable) && ast_test_flag(&flags, OPT_FLOAT)) {
00244          double hrtime;
00245 
00246          if(!ast_tvzero(cdr->end))
00247             hrtime = (double)(ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0);
00248          else
00249             hrtime = (double)(ast_tvdiff_us(ast_tvnow(), cdr->start) / 1000000.0);
00250 
00251          snprintf(buf, len, "%lf", hrtime);
00252 
00253       if (!ast_strlen_zero(buf)) {
00254          ret = buf;
00255       }
00256    } else {
00257       ast_cdr_getvar(cdr, args.variable, &ret, buf, len,
00258                 ast_test_flag(&flags, OPT_RECURSIVE),
00259                ast_test_flag(&flags, OPT_UNPARSED));
00260    }
00261 
00262    ast_channel_unlock(chan);
00263    return ret ? 0 : -1;
00264 }
00265 
00266 static int cdr_write(struct ast_channel *chan, const char *cmd, char *parse,
00267            const char *value)
00268 {
00269    struct ast_cdr *cdr;
00270    struct ast_flags flags = { 0 };
00271    AST_DECLARE_APP_ARGS(args,
00272               AST_APP_ARG(variable);
00273               AST_APP_ARG(options);
00274    );
00275 
00276    if (ast_strlen_zero(parse) || !value || !chan)
00277       return -1;
00278 
00279    ast_channel_lock(chan);
00280    cdr = chan->cdr;
00281    if (!cdr) {
00282       ast_channel_unlock(chan);
00283       return -1;
00284    }
00285 
00286    AST_STANDARD_APP_ARGS(args, parse);
00287 
00288    if (!ast_strlen_zero(args.options))
00289       ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
00290 
00291    if (ast_test_flag(&flags, OPT_LAST))
00292       while (cdr->next)
00293          cdr = cdr->next;
00294 
00295    if (!strcasecmp(args.variable, "accountcode"))  /* the 'l' flag doesn't apply to setting the accountcode, userfield, or amaflags */
00296       ast_cdr_setaccount(chan, value);
00297    else if (!strcasecmp(args.variable, "peeraccount"))
00298       ast_cdr_setpeeraccount(chan, value);
00299    else if (!strcasecmp(args.variable, "userfield"))
00300       ast_cdr_setuserfield(chan, value);
00301    else if (!strcasecmp(args.variable, "amaflags"))
00302       ast_cdr_setamaflags(chan, value);
00303    else
00304       ast_cdr_setvar(cdr, args.variable, value, ast_test_flag(&flags, OPT_RECURSIVE));
00305       /* No need to worry about the u flag, as all fields for which setting
00306        * 'u' would do anything are marked as readonly. */
00307 
00308    ast_channel_unlock(chan);
00309    return 0;
00310 }
00311 
00312 static struct ast_custom_function cdr_function = {
00313    .name = "CDR",
00314    .read = cdr_read,
00315    .write = cdr_write,
00316 };
00317 
00318 static int unload_module(void)
00319 {
00320    return ast_custom_function_unregister(&cdr_function);
00321 }
00322 
00323 static int load_module(void)
00324 {
00325    return ast_custom_function_register(&cdr_function);
00326 }
00327 
00328 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Detail Record (CDR) dialplan function");

Generated on Sat Mar 10 01:54:18 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7