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