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: 118858 $")
00032
00033 #include <stdlib.h>
00034 #include <stdio.h>
00035 #include <string.h>
00036 #include <unistd.h>
00037
00038 #include "asterisk/file.h"
00039 #include "asterisk/logger.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/cdr.h"
00043 #include "asterisk/app.h"
00044 #include "asterisk/module.h"
00045
00046 static char *app = "ForkCDR";
00047 static char *synopsis =
00048 "Forks the Call Data Record";
00049 static char *descrip =
00050 " ForkCDR([options]): Causes the Call Data Record to fork an additional\n"
00051 "cdr record starting from the time of the fork call\n"
00052 " Options:\n"
00053 " a - update the answer time on the NEW CDR just after it's been inited..\n"
00054 " The new CDR may have been answered already, the reset that forkcdr.\n"
00055 " does will erase the answer time. This will bring it back, but.\n"
00056 " the answer time will be a copy of the fork/start time. It will.\n"
00057 " only do this if the initial cdr was indeed already answered..\n"
00058 " D - Copy the disposition forward from the old cdr, after the .\n"
00059 " init..\n"
00060 " d - Clear the dstchannel on the new CDR after reset..\n"
00061 " e - end the original CDR. Do this after all the necc. data.\n"
00062 " is copied from the original CDR to the new forked CDR..\n"
00063 " R - do NOT reset the new cdr..\n"
00064 " s(name=val) - Set the CDR var 'name' in the original CDR, with value.\n"
00065 " 'val'.\n"
00066 " v - When the new CDR is forked, it gets a copy of the vars attached\n"
00067 " to the current CDR. The vars attached to the original CDR are removed\n"
00068 " unless this option is specified.\n";
00069
00070
00071 enum {
00072 OPT_SETANS = (1 << 0),
00073 OPT_SETDISP = (1 << 1),
00074 OPT_RESETDEST = (1 << 2),
00075 OPT_ENDCDR = (1 << 3),
00076 OPT_NORESET = (1 << 4),
00077 OPT_KEEPVARS = (1 << 5),
00078 OPT_VARSET = (1 << 6),
00079 };
00080
00081 enum {
00082 OPT_ARG_VARSET = 0,
00083
00084 OPT_ARG_ARRAY_SIZE,
00085 };
00086
00087 AST_APP_OPTIONS(forkcdr_exec_options, {
00088 AST_APP_OPTION('a', OPT_SETANS),
00089 AST_APP_OPTION('d', OPT_SETDISP),
00090 AST_APP_OPTION('D', OPT_RESETDEST),
00091 AST_APP_OPTION('e', OPT_ENDCDR),
00092 AST_APP_OPTION('R', OPT_NORESET),
00093 AST_APP_OPTION_ARG('s', OPT_VARSET, OPT_ARG_VARSET),
00094 AST_APP_OPTION('v', OPT_KEEPVARS),
00095 });
00096
00097 static void ast_cdr_fork(struct ast_channel *chan, struct ast_flags optflags, char *set)
00098 {
00099 struct ast_cdr *cdr;
00100 struct ast_cdr *newcdr;
00101 struct ast_flags flags = { AST_CDR_FLAG_KEEP_VARS };
00102
00103 cdr = chan->cdr;
00104
00105 while (cdr->next)
00106 cdr = cdr->next;
00107
00108 if (!(newcdr = ast_cdr_dup(cdr)))
00109 return;
00110
00111 ast_cdr_append(cdr, newcdr);
00112
00113 if (!ast_test_flag(&optflags, OPT_NORESET))
00114 ast_cdr_reset(newcdr, &flags);
00115
00116 if (!ast_test_flag(cdr, AST_CDR_FLAG_KEEP_VARS))
00117 ast_cdr_free_vars(cdr, 0);
00118
00119 if (!ast_strlen_zero(set)) {
00120 char *varname = ast_strdupa(set), *varval;
00121 varval = strchr(varname,'=');
00122 if (varval) {
00123 *varval = 0;
00124 varval++;
00125 ast_cdr_setvar(cdr, varname, varval, 0);
00126 }
00127 }
00128
00129 if (ast_test_flag(&optflags, OPT_SETANS) && !ast_tvzero(cdr->answer))
00130 newcdr->answer = newcdr->start;
00131
00132 if (ast_test_flag(&optflags, OPT_SETDISP))
00133 newcdr->disposition = cdr->disposition;
00134
00135 if (ast_test_flag(&optflags, OPT_RESETDEST))
00136 newcdr->dstchannel[0] = 0;
00137
00138 if (ast_test_flag(&optflags, OPT_ENDCDR))
00139 ast_cdr_end(cdr);
00140
00141 ast_set_flag(cdr, AST_CDR_FLAG_CHILD | AST_CDR_FLAG_LOCKED);
00142 }
00143
00144 static int forkcdr_exec(struct ast_channel *chan, void *data)
00145 {
00146 int res = 0;
00147 struct ast_module_user *u;
00148 char *argcopy = NULL;
00149 struct ast_flags flags = {0};
00150 char *opts[OPT_ARG_ARRAY_SIZE];
00151 AST_DECLARE_APP_ARGS(arglist,
00152 AST_APP_ARG(options);
00153 );
00154
00155 if (!chan->cdr) {
00156 ast_log(LOG_WARNING, "Channel does not have a CDR\n");
00157 return 0;
00158 }
00159
00160 u = ast_module_user_add(chan);
00161
00162 argcopy = ast_strdupa(data);
00163
00164 AST_STANDARD_APP_ARGS(arglist, argcopy);
00165
00166 if (!ast_strlen_zero(arglist.options)) {
00167 ast_app_parse_options(forkcdr_exec_options, &flags, opts, arglist.options);
00168 } else
00169 opts[OPT_ARG_VARSET] = 0;
00170
00171 if (!ast_strlen_zero(data))
00172 ast_set2_flag(chan->cdr, ast_test_flag(&flags, OPT_KEEPVARS), AST_CDR_FLAG_KEEP_VARS);
00173
00174 ast_cdr_fork(chan, flags, opts[OPT_ARG_VARSET]);
00175
00176 ast_module_user_remove(u);
00177 return res;
00178 }
00179
00180 static int unload_module(void)
00181 {
00182 int res;
00183
00184 res = ast_unregister_application(app);
00185
00186 ast_module_user_hangup_all();
00187
00188 return res;
00189 }
00190
00191 static int load_module(void)
00192 {
00193 return ast_register_application(app, forkcdr_exec, synopsis, descrip);
00194 }
00195
00196 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Fork The CDR into 2 separate entities");