Index: apps/app_forkcdr.c =================================================================== --- apps/app_forkcdr.c (revision 119424) +++ apps/app_forkcdr.c (working copy) @@ -50,11 +50,13 @@ " ForkCDR([options]): Causes the Call Data Record to fork an additional\n" "cdr record starting from the time of the fork call\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" +" 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" @@ -76,6 +78,7 @@ OPT_NORESET = (1 << 4), OPT_KEEPVARS = (1 << 5), OPT_VARSET = (1 << 6), + OPT_ANSLOCK = (1 << 7), }; enum { @@ -86,6 +89,7 @@ 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), @@ -138,6 +142,9 @@ 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); + ast_set_flag(cdr, AST_CDR_FLAG_CHILD | AST_CDR_FLAG_LOCKED); } Index: funcs/func_cdr.c =================================================================== --- funcs/func_cdr.c (revision 119424) +++ funcs/func_cdr.c (working copy) @@ -88,6 +88,7 @@ static int cdr_write(struct ast_channel *chan, 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); @@ -97,19 +98,26 @@ 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. */ @@ -143,11 +151,13 @@ " 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" -" 3 = FAILED\n" -" 4 = ANSWERED\n" +" 2 = BUSY\n" +" 3 = FAILED\n" +" 4 = ANSWERED\n" " raw values for amaflags:\n" " 1 = OMIT\n" " 2 = BILLING\n" Index: include/asterisk/cdr.h =================================================================== --- include/asterisk/cdr.h (revision 119424) +++ include/asterisk/cdr.h (working copy) @@ -24,11 +24,12 @@ #define _ASTERISK_CDR_H #include -#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_NULL 0 #define AST_CDR_FAILED (1 << 0) @@ -39,10 +40,10 @@ /*! AMA Flags */ #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" Index: main/cdr.c =================================================================== --- main/cdr.c (revision 119424) +++ main/cdr.c (working copy) @@ -695,6 +695,8 @@ { for (; cdr; cdr = cdr->next) { + if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED)) + continue; check_post(cdr); if (cdr->disposition < AST_CDR_ANSWERED) cdr->disposition = AST_CDR_ANSWERED; @@ -707,6 +709,8 @@ { for (; cdr; cdr = cdr->next) { + if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED)) + continue; if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) { check_post(cdr); if (cdr->disposition < AST_CDR_BUSY) @@ -718,6 +722,8 @@ void ast_cdr_failed(struct ast_cdr *cdr) { for (; cdr; cdr = cdr->next) { + if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED)) + continue; check_post(cdr); if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) { if (cdr->disposition < AST_CDR_FAILED) @@ -731,6 +737,8 @@ char *chan; while (cdr) { + if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED)) + continue; chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : ""; if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED)) ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);