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: 408747 $") 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 /* 00195 * End the original CDR if requested BEFORE appending the new CDR 00196 * otherwise we incorrectly end the new CDR also. 00197 */ 00198 if (ast_test_flag(&optflags, OPT_ENDCDR)) { 00199 ast_cdr_end(cdr); 00200 } 00201 00202 ast_cdr_append(cdr, newcdr); 00203 00204 if (!ast_test_flag(&optflags, OPT_NORESET)) 00205 ast_cdr_reset(newcdr, &flags); 00206 00207 if (!ast_test_flag(cdr, AST_CDR_FLAG_KEEP_VARS)) 00208 ast_cdr_free_vars(cdr, 0); 00209 00210 if (!ast_strlen_zero(set)) { 00211 char *varname = ast_strdupa(set), *varval; 00212 varval = strchr(varname,'='); 00213 if (varval) { 00214 *varval = 0; 00215 varval++; 00216 ast_cdr_setvar(cdr, varname, varval, 0); 00217 } 00218 } 00219 00220 if (ast_test_flag(&optflags, OPT_SETANS) && !ast_tvzero(cdr->answer)) 00221 newcdr->answer = newcdr->start; 00222 00223 if (ast_test_flag(&optflags, OPT_SETDISP)) 00224 newcdr->disposition = cdr->disposition; 00225 00226 if (ast_test_flag(&optflags, OPT_RESETDEST)) 00227 newcdr->dstchannel[0] = 0; 00228 00229 if (ast_test_flag(&optflags, OPT_ANSLOCK)) 00230 ast_set_flag(cdr, AST_CDR_FLAG_ANSLOCKED); 00231 00232 if (ast_test_flag(&optflags, OPT_DONTOUCH)) 00233 ast_set_flag(cdr, AST_CDR_FLAG_DONT_TOUCH); 00234 00235 ast_set_flag(cdr, AST_CDR_FLAG_CHILD | AST_CDR_FLAG_LOCKED); 00236 } 00237 00238 static int forkcdr_exec(struct ast_channel *chan, const char *data) 00239 { 00240 int res = 0; 00241 char *argcopy = NULL; 00242 struct ast_cdr *cdr; 00243 struct ast_flags flags = {0}; 00244 char *opts[OPT_ARG_ARRAY_SIZE]; 00245 AST_DECLARE_APP_ARGS(arglist, 00246 AST_APP_ARG(options); 00247 ); 00248 00249 if (!(cdr = chan->cdr)) { 00250 ast_log(LOG_WARNING, "Channel does not have a CDR\n"); 00251 return 0; 00252 } 00253 00254 argcopy = ast_strdupa(data); 00255 00256 AST_STANDARD_APP_ARGS(arglist, argcopy); 00257 00258 opts[OPT_ARG_VARSET] = 0; 00259 00260 if (!ast_strlen_zero(arglist.options)) 00261 ast_app_parse_options(forkcdr_exec_options, &flags, opts, arglist.options); 00262 00263 if (!ast_strlen_zero(data)) { 00264 int keepvars = ast_test_flag(&flags, OPT_KEEPVARS) ? 1 : 0; 00265 while (cdr->next) { 00266 cdr = cdr->next; 00267 } 00268 ast_set2_flag(cdr, keepvars, AST_CDR_FLAG_KEEP_VARS); 00269 } 00270 00271 ast_cdr_fork(chan, flags, opts[OPT_ARG_VARSET]); 00272 00273 return res; 00274 } 00275 00276 static int unload_module(void) 00277 { 00278 return ast_unregister_application(app); 00279 } 00280 00281 static int load_module(void) 00282 { 00283 return ast_register_application_xml(app, forkcdr_exec); 00284 } 00285 00286 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Fork The CDR into 2 separate entities");