aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormurf <murf@f38db490-d61c-443f-a65b-d21fe96a405b>2008-06-12 14:38:46 +0000
committermurf <murf@f38db490-d61c-443f-a65b-d21fe96a405b>2008-06-12 14:38:46 +0000
commita8ccf75d8fc86b365be1cc93dbcbab6697119bf4 (patch)
tree2c8871ffc414e7333bc174d1e67c6c4935ff86b3
parenta2d7be26a43b4698e3653f32d23c127f0e054c1d (diff)
Merged revisions 122091 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk ................ r122091 | murf | 2008-06-12 08:28:01 -0600 (Thu, 12 Jun 2008) | 45 lines Merged revisions 122046 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r122046 | murf | 2008-06-12 07:47:34 -0600 (Thu, 12 Jun 2008) | 37 lines (closes issue #10668) Reported by: arkadia Tested by: murf, arkadia Options added to forkCDR() app and the CDR() func to remove some roadblocks for CDR applications. The "show application ForkCDR" output was upgraded to more fully explain the inner workings of forkCDR. The A option was added to forkCDR to force the CDR system to NOT change the disposition on the original CDR, after the fork. This involves ast_cdr_answer, _busy, _failed, and so on. The T option was added to forkCDR to force obedience of the cdr LOCKED flag in the ast_cdr_end, all the disposition changing funcs (ast_cdr_answer, etc), and in the ast_cdr_setvar func. The CHANGES file was updated to explain ALL the new options added to satisfy this bug report (and some requests made verbally and via email, irc, etc, over the past months/year) The 's' option was added to the CDR() func, to force it to skip LOCKED cdr's in the chain. Again, the new options should be totally transparent to existing apps! Current behavior of CDR, forkCDR, and the rest of the CDR system should not change one little bit. Until you add the new options, at least! ........ ................ git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.6.0@122126 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--CHANGES7
-rw-r--r--apps/app_forkcdr.c83
-rw-r--r--funcs/func_cdr.c24
-rw-r--r--include/asterisk/cdr.h18
-rw-r--r--main/cdr.c21
5 files changed, 140 insertions, 13 deletions
diff --git a/CHANGES b/CHANGES
index 4e91b06df..5901f28ba 100644
--- a/CHANGES
+++ b/CHANGES
@@ -382,6 +382,13 @@ Other Dialplan Application Changes
* The ChannelRedirect application no longer exits the dialplan if the given channel
does not exist. It will now set the CHANNELREDIRECT_STATUS variable to SUCCESS upon success
or NOCHANNEL if the given channel was not found.
+ * ForkCDR has new options: 'a' updates the answer time on the new CDR; 'A' locks
+ answer times, disposition, on orig CDR against updates; 'D' Copies the disposition
+ from the orig CDR to the new CDR after reset; 'e' sets the 'end' time on the
+ original CDR; 'R' prevents the new CDR from being reset; 's(var=val)' adds/changes
+ the 'var' variable on the original CDR; 'T' forces ast_cdr_end(), ast_cdr_answer(),
+ _busy(), failed(), etc, to all obey the LOCKED flag on cdr's in the chain, and
+ also the ast_cdr_setvar() func.
Music On Hold Changes
---------------------
diff --git a/apps/app_forkcdr.c b/apps/app_forkcdr.c
index 8d01a829c..4c6e620fb 100644
--- a/apps/app_forkcdr.c
+++ b/apps/app_forkcdr.c
@@ -42,21 +42,82 @@ static char *synopsis =
"Forks the Call Data Record";
static char *descrip =
" ForkCDR([options]): Causes the Call Data Record to fork an additional\n"
-"cdr record starting from the time of the fork call\n"
+"cdr record starting from the time of the fork call. This new cdr record will\n"
+"be linked to end of the list of cdr records attached to the channel. The original CDR is\n"
+"has a LOCKED flag set, which forces most cdr operations to skip it, except\n"
+"for the functions that set the answer and end times, which ignore the LOCKED\n"
+"flag. This allows all the cdr records in the channel to be 'ended' together\n"
+"when the channel is closed.\n"
+"The CDR() func (when setting CDR values) normally ignores the LOCKED flag also,\n"
+"but has options to vary its behavior. The 'T' option (described below), can\n"
+"override this behavior, but beware the risks.\n"
+"\n"
+"Detailed Behavior Description:\n"
+"First, this app finds the last cdr record in the list, and makes\n"
+"a copy of it. This new copy will be the newly forked cdr record.\n"
+"Next, this new record is linked to the end of the cdr record list.\n"
+"Next, The new cdr record is RESET (unless you use an option to prevent this)\n"
+"This means that:\n"
+" 1. All flags are unset on the cdr record\n"
+" 2. the start, end, and answer times are all set to zero.\n"
+" 3. the billsec and duration fields are set to zero.\n"
+" 4. the start time is set to the current time.\n"
+" 5. the disposition is set to NULL.\n"
+"Next, unless you specified the 'v' option, all variables will be\n"
+"removed from the original cdr record. Thus, the 'v' option allows\n"
+"any CDR variables to be replicated to all new forked cdr records.\n"
+"Without the 'v' option, the variables on the original are effectively\n"
+"moved to the new forked cdr record.\n"
+"Next, if the 's' option is set, the provided variable and value\n"
+"are set on the original cdr record.\n"
+"Next, if the 'a' option is given, and the original cdr record has an\n"
+"answer time set, then the new forked cdr record will have its answer\n"
+"time set to its start time. If the old answer time were carried forward,\n"
+"the answer time would be earlier than the start time, giving strange\n"
+"duration and billsec times.\n"
+"Next, if the 'd' option was specified, the disposition is copied from\n"
+"the original cdr record to the new forked cdr.\n"
+"Next, if the 'D' option was specified, the destination channel field\n"
+"in the new forked CDR is erased.\n"
+"Next, if the 'e' option was specified, the 'end' time for the original\n"
+"cdr record is set to the current time. Future hang-up or ending events\n"
+"will not override this time stamp.\n"
+"Next, If the 'A' option is specified, the original cdr record will have\n"
+"it ANS_LOCKED flag set, which prevent future call dispostion events\n"
+"from updating the original cdr record's disposition. Normally, an\n"
+"'ANSWERED' event would mark all cdr records in the chain as 'ANSWERED'.\n"
+"Next, if the 'T' option is specified, the original cdr record will have\n"
+"its 'DONT_TOUCH' flag set, which will force the cdr_answer, cdr_end, and\n"
+"cdr_setvar functions to leave that cdr record alone.\n"
+"And, last but not least, the original cdr record has its LOCKED flag\n"
+"set. Almost all internal CDR functions (except for the funcs that set\n"
+"the end, and answer times, and set a variable) will honor this flag\n"
+"and leave a LOCKED cdr record alone.\n"
+"This means that the newly created forked cdr record will affected\n"
+"by events transpiring within Asterisk, with the previously noted\n"
+"exceptions.\n"
" Options:\n"
-" a - update the answer time on the NEW CDR just after it's been inited..\n"
+" a - update the answer time on the NEW CDR just after it's been inited..\n"
" The new CDR may have been answered already, the reset that forkcdr.\n"
-" does will erase the answer time. This will bring it back, but.\n"
+" does will erase the answer time. This will bring it back, but\n"
" the answer time will be a copy of the fork/start time. It will.\n"
" only do this if the initial cdr was indeed already answered..\n"
-" D - Copy the disposition forward from the old cdr, after the .\n"
+" A - Lock the original CDR against the answer time being updated.\n"
+" This will allow the disposition on the original CDR to remain the same.\n"
+" d - Copy the disposition forward from the old cdr, after the .\n"
" init..\n"
-" d - Clear the dstchannel on the new CDR after reset..\n"
-" e - end the original CDR. Do this after all the necc. data.\n"
+" D - Clear the dstchannel on the new CDR after reset..\n"
+" e - end the original CDR. Do this after all the necc. data.\n"
" is copied from the original CDR to the new forked CDR..\n"
" R - do NOT reset the new cdr..\n"
" s(name=val) - Set the CDR var 'name' in the original CDR, with value.\n"
" 'val'.\n"
+" T - Mark the original CDR with a DONT_TOUCH flag. setvar, answer, and end\n"
+" cdr funcs will obey this flag; normally they don't honor the LOCKED\n"
+" flag set on the original CDR record.\n"
+" Beware-- using this flag may cause CDR's not to have their end times\n"
+" updated! It is suggested that if you specify this flag, you might\n"
+" wish to use the 'e' flag as well!\n"
" v - When the new CDR is forked, it gets a copy of the vars attached\n"
" to the current CDR. The vars attached to the original CDR are removed\n"
" unless this option is specified.\n";
@@ -70,6 +131,8 @@ enum {
OPT_NORESET = (1 << 4),
OPT_KEEPVARS = (1 << 5),
OPT_VARSET = (1 << 6),
+ OPT_ANSLOCK = (1 << 7),
+ OPT_DONTOUCH = (1 << 8),
};
enum {
@@ -80,11 +143,13 @@ enum {
AST_APP_OPTIONS(forkcdr_exec_options, {
AST_APP_OPTION('a', OPT_SETANS),
+ AST_APP_OPTION('A', OPT_ANSLOCK),
AST_APP_OPTION('d', OPT_SETDISP),
AST_APP_OPTION('D', OPT_RESETDEST),
AST_APP_OPTION('e', OPT_ENDCDR),
AST_APP_OPTION('R', OPT_NORESET),
AST_APP_OPTION_ARG('s', OPT_VARSET, OPT_ARG_VARSET),
+ AST_APP_OPTION('T', OPT_DONTOUCH),
AST_APP_OPTION('v', OPT_KEEPVARS),
});
@@ -132,6 +197,12 @@ static void ast_cdr_fork(struct ast_channel *chan, struct ast_flags optflags, ch
if (ast_test_flag(&optflags, OPT_ENDCDR))
ast_cdr_end(cdr);
+ if (ast_test_flag(&optflags, OPT_ANSLOCK))
+ ast_set_flag(cdr, AST_CDR_FLAG_ANSLOCKED);
+
+ if (ast_test_flag(&optflags, OPT_DONTOUCH))
+ ast_set_flag(cdr, AST_CDR_FLAG_DONT_TOUCH);
+
ast_set_flag(cdr, AST_CDR_FLAG_CHILD | AST_CDR_FLAG_LOCKED);
}
diff --git a/funcs/func_cdr.c b/funcs/func_cdr.c
index a1004e679..3ea1a3008 100644
--- a/funcs/func_cdr.c
+++ b/funcs/func_cdr.c
@@ -40,11 +40,13 @@ enum {
OPT_RECURSIVE = (1 << 0),
OPT_UNPARSED = (1 << 1),
OPT_LAST = (1 << 2),
+ OPT_SKIPLOCKED = (1 << 3),
} cdr_option_flags;
AST_APP_OPTIONS(cdr_func_options, {
AST_APP_OPTION('l', OPT_LAST),
AST_APP_OPTION('r', OPT_RECURSIVE),
+ AST_APP_OPTION('s', OPT_SKIPLOCKED),
AST_APP_OPTION('u', OPT_UNPARSED),
});
@@ -74,6 +76,10 @@ static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
while (cdr->next)
cdr = cdr->next;
+ if (ast_test_flag(&flags, OPT_SKIPLOCKED))
+ while (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED) && cdr->next)
+ cdr = cdr->next;
+
ast_cdr_getvar(cdr, args.variable, &ret, buf, len,
ast_test_flag(&flags, OPT_RECURSIVE),
ast_test_flag(&flags, OPT_UNPARSED));
@@ -84,6 +90,7 @@ static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
static int cdr_write(struct ast_channel *chan, const char *cmd, char *parse,
const char *value)
{
+ struct ast_cdr *cdr = chan ? chan->cdr : NULL;
struct ast_flags flags = { 0 };
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(variable);
@@ -93,19 +100,26 @@ static int cdr_write(struct ast_channel *chan, const char *cmd, char *parse,
if (ast_strlen_zero(parse) || !value || !chan)
return -1;
+ if (!cdr)
+ return -1;
+
AST_STANDARD_APP_ARGS(args, parse);
if (!ast_strlen_zero(args.options))
ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
- if (!strcasecmp(args.variable, "accountcode"))
+ if (ast_test_flag(&flags, OPT_LAST))
+ while (cdr->next)
+ cdr = cdr->next;
+
+ if (!strcasecmp(args.variable, "accountcode")) /* the 'l' flag doesn't apply to setting the accountcode, userfield, or amaflags */
ast_cdr_setaccount(chan, value);
else if (!strcasecmp(args.variable, "userfield"))
ast_cdr_setuserfield(chan, value);
else if (!strcasecmp(args.variable, "amaflags"))
ast_cdr_setamaflags(chan, value);
- else if (chan->cdr)
- ast_cdr_setvar(chan->cdr, args.variable, value, ast_test_flag(&flags, OPT_RECURSIVE));
+ else
+ ast_cdr_setvar(cdr, args.variable, value, ast_test_flag(&flags, OPT_RECURSIVE));
/* No need to worry about the u flag, as all fields for which setting
* 'u' would do anything are marked as readonly. */
@@ -122,6 +136,8 @@ static struct ast_custom_function cdr_function = {
"Options:\n"
" 'l' uses the most recent CDR on a channel with multiple records\n"
" 'r' searches the entire stack of CDRs on the channel\n"
+" 's' skips any CDR's that are marked 'LOCKED' due to forkCDR() calls.\n"
+" (on setting/writing CDR vars only)\n"
" 'u' retrieves the raw, unprocessed value\n"
" For example, 'start', 'answer', and 'end' will be retrieved as epoch\n"
" values, when the 'u' option is passed, but formatted as YYYY-MM-DD HH:MM:SS\n"
@@ -139,6 +155,8 @@ static struct ast_custom_function cdr_function = {
" a name not on the above list, and create your own\n"
" variable, whose value can be changed with this function,\n"
" and this variable will be stored on the cdr.\n"
+" For setting CDR values, the 'l' flag does not apply to\n"
+" setting the accountcode, userfield, or amaflags.\n"
" raw values for disposition:\n"
" 1 = NO ANSWER\n"
" 2 = BUSY\n"
diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h
index fbab3f53f..addef04ea 100644
--- a/include/asterisk/cdr.h
+++ b/include/asterisk/cdr.h
@@ -24,11 +24,13 @@
#define _ASTERISK_CDR_H
#include <sys/time.h>
-#define AST_CDR_FLAG_KEEP_VARS (1 << 0)
+#define AST_CDR_FLAG_KEEP_VARS (1 << 0)
#define AST_CDR_FLAG_POSTED (1 << 1)
#define AST_CDR_FLAG_LOCKED (1 << 2)
#define AST_CDR_FLAG_CHILD (1 << 3)
-#define AST_CDR_FLAG_POST_DISABLED (1 << 4)
+#define AST_CDR_FLAG_POST_DISABLED (1 << 4)
+#define AST_CDR_FLAG_ANSLOCKED (1 << 5)
+#define AST_CDR_FLAG_DONT_TOUCH (1 << 6)
#define AST_CDR_FLAG_POST_ENABLE (1 << 5)
/*! \name CDR Flags */
@@ -44,11 +46,11 @@
/*@{ */
#define AST_CDR_OMIT (1)
#define AST_CDR_BILLING (2)
-#define AST_CDR_DOCUMENTATION (3)
+#define AST_CDR_DOCUMENTATION (3)
/*@} */
#define AST_MAX_USER_FIELD 256
-#define AST_MAX_ACCOUNT_CODE 20
+#define AST_MAX_ACCOUNT_CODE 20
/* Include channel.h after relevant declarations it will need */
#include "asterisk/channel.h"
@@ -196,12 +198,17 @@ void ast_cdr_answer(struct ast_cdr *cdr);
* \brief A call wasn't answered
* \param cdr the cdr you wish to associate with the call
* Marks the channel disposition as "NO ANSWER"
+ * Will skip CDR's in chain with ANS_LOCK bit set. (see
+ * forkCDR() application.
*/
extern void ast_cdr_noanswer(struct ast_cdr *cdr);
/*!
* \brief Busy a call
* \param cdr the cdr you wish to associate with the call
+ * Marks the channel disposition as "BUSY"
+ * Will skip CDR's in chain with ANS_LOCK bit set. (see
+ * forkCDR() application.
* Returns nothing
*/
void ast_cdr_busy(struct ast_cdr *cdr);
@@ -209,6 +216,9 @@ void ast_cdr_busy(struct ast_cdr *cdr);
/*!
* \brief Fail a call
* \param cdr the cdr you wish to associate with the call
+ * Marks the channel disposition as "FAILED"
+ * Will skip CDR's in chain with ANS_LOCK bit set. (see
+ * forkCDR() application.
* Returns nothing
*/
void ast_cdr_failed(struct ast_cdr *cdr);
diff --git a/main/cdr.c b/main/cdr.c
index ee6819aae..921b2915b 100644
--- a/main/cdr.c
+++ b/main/cdr.c
@@ -306,6 +306,8 @@ int ast_cdr_setvar(struct ast_cdr *cdr, const char *name, const char *value, int
}
for (; cdr; cdr = recur ? cdr->next : NULL) {
+ if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
+ continue;
headp = &cdr->varshead;
AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
if (!strcasecmp(ast_var_name(newvariable), name)) {
@@ -689,6 +691,10 @@ void ast_cdr_answer(struct ast_cdr *cdr)
{
for (; cdr; cdr = cdr->next) {
+ if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
+ continue;
+ if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
+ continue;
check_post(cdr);
if (cdr->disposition < AST_CDR_ANSWERED)
cdr->disposition = AST_CDR_ANSWERED;
@@ -701,6 +707,10 @@ void ast_cdr_busy(struct ast_cdr *cdr)
{
for (; cdr; cdr = cdr->next) {
+ if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
+ continue;
+ if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
+ continue;
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
check_post(cdr);
if (cdr->disposition < AST_CDR_BUSY)
@@ -712,6 +722,11 @@ void ast_cdr_busy(struct ast_cdr *cdr)
void ast_cdr_failed(struct ast_cdr *cdr)
{
for (; cdr; cdr = cdr->next) {
+ if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
+ continue;
+ if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
+ continue;
+ check_post(cdr);
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
check_post(cdr);
if (cdr->disposition < AST_CDR_FAILED)
@@ -725,6 +740,10 @@ void ast_cdr_noanswer(struct ast_cdr *cdr)
char *chan;
while (cdr) {
+ if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
+ continue;
+ if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
+ continue;
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
@@ -847,6 +866,8 @@ int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *c)
void ast_cdr_end(struct ast_cdr *cdr)
{
for ( ; cdr ; cdr = cdr->next) {
+ if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
+ continue;
check_post(cdr);
if (ast_tvzero(cdr->end))
cdr->end = ast_tvnow();