Sat Mar 10 01:53:57 2012

Asterisk developer's documentation


app_forkcdr.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Anthony Minessale anthmct@yahoo.com
00005  * Development of this app Sponsered/Funded  by TAAN Softworks Corp
00006  *
00007  * See http://www.asterisk.org for more information about
00008  * the Asterisk project. Please do not directly contact
00009  * any of the maintainers of this project for assistance;
00010  * the project provides a web site, mailing lists and IRC
00011  * channels for your use.
00012  *
00013  * This program is free software, distributed under the terms of
00014  * the GNU General Public License Version 2. See the LICENSE file
00015  * at the top of the source tree.
00016  */
00017 
00018 /*! \file
00019  *
00020  * \brief Fork CDR application
00021  *
00022  * \author Anthony Minessale anthmct@yahoo.com
00023  *
00024  * \note Development of this app Sponsored/Funded by TAAN Softworks Corp
00025  * 
00026  * \ingroup applications
00027  */
00028 
00029 /*** MODULEINFO
00030    <support_level>core</support_level>
00031  ***/
00032 
00033 #include "asterisk.h"
00034 
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00036 
00037 #include "asterisk/file.h"
00038 #include "asterisk/channel.h"
00039 #include "asterisk/pbx.h"
00040 #include "asterisk/cdr.h"
00041 #include "asterisk/app.h"
00042 #include "asterisk/module.h"
00043 
00044 /*** DOCUMENTATION
00045    <application name="ForkCDR" language="en_US">
00046       <synopsis>
00047          Forks the Call Data Record.
00048       </synopsis>
00049       <syntax>
00050          <parameter name="options">
00051             <optionlist>
00052                <option name="a">
00053                   <para>Update the answer time on the NEW CDR just after it's been inited.
00054                   The new CDR may have been answered already. The reset that forkcdr does
00055                   will erase the answer time. This will bring it back, but the answer time
00056                   will be a copy of the fork/start time. It will only do this if the initial
00057                   cdr was indeed already answered.</para>
00058                </option>
00059                <option name="A">
00060                   <para>Lock the original CDR against the answer time being updated. This
00061                   will allow the disposition on the original CDR to remain the same.</para>
00062                </option>
00063                <option name="d">
00064                   <para>Copy the disposition forward from the old cdr, after the init.</para>
00065                </option>
00066                <option name="D">
00067                   <para>Clear the <literal>dstchannel</literal> on the new CDR after
00068                   reset.</para>
00069                </option>
00070                <option name="e">
00071                   <para>End the original CDR. Do this after all the necessary data is copied
00072                   from the original CDR to the new forked CDR.</para>
00073                </option>
00074                <option name="r">
00075                   <para>Do <emphasis>NOT</emphasis> reset the new cdr.</para>
00076                </option>
00077                <option name="s(name=val)">
00078                   <para>Set the CDR var <replaceable>name</replaceable> in the original CDR,
00079                   with value <replaceable>val</replaceable>.</para>
00080                </option>
00081                <option name="T">
00082                   <para>Mark the original CDR with a DONT_TOUCH flag. setvar, answer, and end
00083                   cdr funcs will obey this flag; normally they don't honor the LOCKED flag
00084                   set on the original CDR record.</para>
00085                   <note><para>Using this flag may cause CDR's not to have their end times
00086                   updated! It is suggested that if you specify this flag, you might wish
00087                   to use the <literal>e</literal> flag as well!.</para></note>
00088                </option>
00089                <option name="v">
00090                   <para>When the new CDR is forked, it gets a copy of the vars attached to
00091                   the current CDR. The vars attached to the original CDR are removed unless
00092                   this option is specified.</para>
00093                </option>
00094             </optionlist>
00095          </parameter>
00096       </syntax>
00097       <description>
00098          <para> Causes the Call Data Record to fork an additional cdr record starting from the time
00099          of the fork call. This new cdr record will be linked to end of the list of cdr records attached
00100          to the channel.   The original CDR has a LOCKED flag set, which forces most cdr operations to skip
00101          it, except for the functions that set the answer and end times, which ignore the LOCKED flag. This
00102          allows all the cdr records in the channel to be 'ended' together when the channel is closed.</para>
00103          <para>The CDR() func (when setting CDR values) normally ignores the LOCKED flag also, but has options
00104          to vary its behavior. The 'T' option (described below), can override this behavior, but beware
00105          the risks.</para>
00106          <para>First, this app finds the last cdr record in the list, and makes a copy of it. This new copy
00107          will be the newly forked cdr record. Next, this new record is linked to the end of the cdr record list.
00108          Next, The new cdr record is RESET (unless you use an option to prevent this)</para>
00109          <para>This means that:</para>
00110          <para>   1. All flags are unset on the cdr record</para>
00111          <para>   2. the start, end, and answer times are all set to zero.</para>
00112          <para>   3. the billsec and duration fields are set to zero.</para>
00113          <para>   4. the start time is set to the current time.</para>
00114          <para>   5. the disposition is set to NULL.</para>
00115          <para>Next, unless you specified the <literal>v</literal> option, all variables will be removed from
00116          the original cdr record. Thus, the <literal>v</literal> option allows any CDR variables to be replicated
00117          to all new forked cdr records. Without the <literal>v</literal> option, the variables on the original
00118          are effectively moved to the new forked cdr record.</para>
00119          <para>Next, if the <literal>s</literal> option is set, the provided variable and value are set on the
00120          original cdr record.</para>
00121          <para>Next, if the <literal>a</literal> option is given, and the original cdr record has an answer time
00122          set, then the new forked cdr record will have its answer time set to its start time. If the old answer
00123          time were carried forward, the answer time would be earlier than the start time, giving strange
00124          duration and billsec times.</para>
00125          <para>If the <literal>d</literal> option was specified, the disposition is copied from
00126          the original cdr record to the new forked cdr. If the <literal>D</literal> option was specified,
00127          the destination channel field in the new forked CDR is erased. If the <literal>e</literal> option
00128          was specified, the 'end' time for the original cdr record is set to the current time. Future hang-up or
00129          ending events will not override this time stamp. If the <literal>A</literal> option is specified,
00130          the original cdr record will have it ANS_LOCKED flag set, which prevent future answer events from updating
00131          the original cdr record's disposition. Normally, an <literal>ANSWERED</literal> event would mark all cdr
00132          records in the chain as <literal>ANSWERED</literal>. If the <literal>T</literal> option is specified,
00133          the original cdr record will have its <literal>DONT_TOUCH</literal> flag set, which will force the
00134          cdr_answer, cdr_end, and cdr_setvar functions to leave that cdr record alone.</para>
00135          <para>And, last but not least, the original cdr record has its LOCKED flag set. Almost all internal
00136          CDR functions (except for the funcs that set the end, and answer times, and set a variable) will honor
00137          this flag and leave a LOCKED cdr record alone. This means that the newly created forked cdr record
00138          will be affected by events transpiring within Asterisk, with the previously noted exceptions.</para>
00139       </description>
00140       <see-also>
00141          <ref type="function">CDR</ref>
00142          <ref type="application">NoCDR</ref>
00143          <ref type="application">ResetCDR</ref>
00144       </see-also>
00145    </application>
00146  ***/
00147 
00148 static char *app = "ForkCDR";
00149 
00150 enum {
00151    OPT_SETANS =            (1 << 0),
00152    OPT_SETDISP =           (1 << 1),
00153    OPT_RESETDEST =         (1 << 2),
00154    OPT_ENDCDR =            (1 << 3),
00155    OPT_NORESET =           (1 << 4),
00156    OPT_KEEPVARS =          (1 << 5),
00157    OPT_VARSET =            (1 << 6),
00158    OPT_ANSLOCK =           (1 << 7),
00159    OPT_DONTOUCH =          (1 << 8),
00160 };
00161 
00162 enum {
00163    OPT_ARG_VARSET = 0,
00164    /* note: this entry _MUST_ be the last one in the enum */
00165    OPT_ARG_ARRAY_SIZE,
00166 };
00167 
00168 AST_APP_OPTIONS(forkcdr_exec_options, {
00169    AST_APP_OPTION('a', OPT_SETANS),
00170    AST_APP_OPTION('A', OPT_ANSLOCK),
00171    AST_APP_OPTION('d', OPT_SETDISP),
00172    AST_APP_OPTION('D', OPT_RESETDEST),
00173    AST_APP_OPTION('e', OPT_ENDCDR),
00174    AST_APP_OPTION('R', OPT_NORESET),
00175    AST_APP_OPTION_ARG('s', OPT_VARSET, OPT_ARG_VARSET),
00176    AST_APP_OPTION('T', OPT_DONTOUCH),
00177    AST_APP_OPTION('v', OPT_KEEPVARS),
00178 });
00179 
00180 static void ast_cdr_fork(struct ast_channel *chan, struct ast_flags optflags, char *set) 
00181 {
00182    struct ast_cdr *cdr;
00183    struct ast_cdr *newcdr;
00184    struct ast_flags flags = { AST_CDR_FLAG_KEEP_VARS };
00185 
00186    cdr = chan->cdr;
00187 
00188    while (cdr->next)
00189       cdr = cdr->next;
00190    
00191    if (!(newcdr = ast_cdr_dup_unique(cdr)))
00192       return;
00193    
00194    ast_cdr_append(cdr, newcdr);
00195 
00196    if (!ast_test_flag(&optflags, OPT_NORESET))
00197       ast_cdr_reset(newcdr, &flags);
00198       
00199    if (!ast_test_flag(cdr, AST_CDR_FLAG_KEEP_VARS))
00200       ast_cdr_free_vars(cdr, 0);
00201    
00202    if (!ast_strlen_zero(set)) {
00203       char *varname = ast_strdupa(set), *varval;
00204       varval = strchr(varname,'=');
00205       if (varval) {
00206          *varval = 0;
00207          varval++;
00208          ast_cdr_setvar(cdr, varname, varval, 0);
00209       }
00210    }
00211    
00212    if (ast_test_flag(&optflags, OPT_SETANS) && !ast_tvzero(cdr->answer))
00213       newcdr->answer = newcdr->start;
00214 
00215    if (ast_test_flag(&optflags, OPT_SETDISP))
00216       newcdr->disposition = cdr->disposition;
00217    
00218    if (ast_test_flag(&optflags, OPT_RESETDEST))
00219       newcdr->dstchannel[0] = 0;
00220    
00221    if (ast_test_flag(&optflags, OPT_ENDCDR))
00222       ast_cdr_end(cdr);
00223 
00224    if (ast_test_flag(&optflags, OPT_ANSLOCK))
00225       ast_set_flag(cdr, AST_CDR_FLAG_ANSLOCKED);
00226    
00227    if (ast_test_flag(&optflags, OPT_DONTOUCH))
00228       ast_set_flag(cdr, AST_CDR_FLAG_DONT_TOUCH);
00229       
00230    ast_set_flag(cdr, AST_CDR_FLAG_CHILD | AST_CDR_FLAG_LOCKED);
00231 }
00232 
00233 static int forkcdr_exec(struct ast_channel *chan, const char *data)
00234 {
00235    int res = 0;
00236    char *argcopy = NULL;
00237    struct ast_flags flags = {0};
00238    char *opts[OPT_ARG_ARRAY_SIZE];
00239    AST_DECLARE_APP_ARGS(arglist,
00240       AST_APP_ARG(options);
00241    );
00242 
00243    if (!chan->cdr) {
00244       ast_log(LOG_WARNING, "Channel does not have a CDR\n");
00245       return 0;
00246    }
00247 
00248    argcopy = ast_strdupa(data);
00249 
00250    AST_STANDARD_APP_ARGS(arglist, argcopy);
00251 
00252    opts[OPT_ARG_VARSET] = 0;
00253 
00254    if (!ast_strlen_zero(arglist.options))
00255       ast_app_parse_options(forkcdr_exec_options, &flags, opts, arglist.options);
00256 
00257    if (!ast_strlen_zero(data)) {
00258       int keepvars = ast_test_flag(&flags, OPT_KEEPVARS) ? 1 : 0;
00259       ast_set2_flag(chan->cdr, keepvars, AST_CDR_FLAG_KEEP_VARS);
00260    }
00261    
00262    ast_cdr_fork(chan, flags, opts[OPT_ARG_VARSET]);
00263 
00264    return res;
00265 }
00266 
00267 static int unload_module(void)
00268 {
00269    return ast_unregister_application(app);
00270 }
00271 
00272 static int load_module(void)
00273 {
00274    return ast_register_application_xml(app, forkcdr_exec);
00275 }
00276 
00277 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Fork The CDR into 2 separate entities");

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