Fix incorrect billing duration reported when batch mode is enabled
[asterisk/asterisk.git] / main / cdr.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Call Detail Record API
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \note Includes code and algorithms from the Zapata library.
26  *
27  * \note We do a lot of checking here in the CDR code to try to be sure we don't ever let a CDR slip
28  * through our fingers somehow.  If someone allocates a CDR, it must be completely handled normally
29  * or a WARNING shall be logged, so that we can best keep track of any escape condition where the CDR
30  * isn't properly generated and posted.
31  */
32
33
34 /*** MODULEINFO
35         <support_level>core</support_level>
36  ***/
37
38 #include "asterisk.h"
39
40 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
41
42 #include <signal.h>
43
44 #include "asterisk/lock.h"
45 #include "asterisk/channel.h"
46 #include "asterisk/cdr.h"
47 #include "asterisk/callerid.h"
48 #include "asterisk/manager.h"
49 #include "asterisk/causes.h"
50 #include "asterisk/linkedlists.h"
51 #include "asterisk/utils.h"
52 #include "asterisk/sched.h"
53 #include "asterisk/config.h"
54 #include "asterisk/cli.h"
55 #include "asterisk/stringfields.h"
56 #include "asterisk/data.h"
57
58 /*** DOCUMENTATION
59  ***/
60
61 /*! Default AMA flag for billing records (CDR's) */
62 int ast_default_amaflags = AST_CDR_DOCUMENTATION;
63 char ast_default_accountcode[AST_MAX_ACCOUNT_CODE];
64
65 struct ast_cdr_beitem {
66         char name[20];
67         char desc[80];
68         ast_cdrbe be;
69         AST_RWLIST_ENTRY(ast_cdr_beitem) list;
70 };
71
72 static AST_RWLIST_HEAD_STATIC(be_list, ast_cdr_beitem);
73
74 struct ast_cdr_batch_item {
75         struct ast_cdr *cdr;
76         struct ast_cdr_batch_item *next;
77 };
78
79 static struct ast_cdr_batch {
80         int size;
81         struct ast_cdr_batch_item *head;
82         struct ast_cdr_batch_item *tail;
83 } *batch = NULL;
84
85
86 static int cdr_sequence =  0;
87
88 static int cdr_seq_inc(struct ast_cdr *cdr);
89
90 static struct ast_sched_context *sched;
91 static int cdr_sched = -1;
92 static pthread_t cdr_thread = AST_PTHREADT_NULL;
93
94 static int enabled;
95 static const int ENABLED_DEFAULT = 1;
96
97 static int batchmode;
98 static const int BATCHMODE_DEFAULT = 0;
99
100 static int unanswered;
101 static const int UNANSWERED_DEFAULT = 0;
102
103 static int congestion;
104 static const int CONGESTION_DEFAULT = 0;
105
106 static int batchsize;
107 static const int BATCH_SIZE_DEFAULT = 100;
108
109 static int batchtime;
110 static const int BATCH_TIME_DEFAULT = 300;
111
112 static int batchscheduleronly;
113 static const int BATCH_SCHEDULER_ONLY_DEFAULT = 0;
114
115 static int batchsafeshutdown;
116 static const int BATCH_SAFE_SHUTDOWN_DEFAULT = 1;
117
118 AST_MUTEX_DEFINE_STATIC(cdr_batch_lock);
119
120 /* these are used to wake up the CDR thread when there's work to do */
121 AST_MUTEX_DEFINE_STATIC(cdr_pending_lock);
122 static ast_cond_t cdr_pending_cond;
123
124 int check_cdr_enabled(void)
125 {
126         return enabled;
127 }
128
129 /*!
130  * \brief Register a CDR driver. Each registered CDR driver generates a CDR
131  * \retval 0 on success.
132  * \retval -1 on error
133  */
134 int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
135 {
136         struct ast_cdr_beitem *i = NULL;
137
138         if (!name)
139                 return -1;
140
141         if (!be) {
142                 ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
143                 return -1;
144         }
145
146         AST_RWLIST_WRLOCK(&be_list);
147         AST_RWLIST_TRAVERSE(&be_list, i, list) {
148                 if (!strcasecmp(name, i->name)) {
149                         ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
150                         AST_RWLIST_UNLOCK(&be_list);
151                         return -1;
152                 }
153         }
154
155         if (!(i = ast_calloc(1, sizeof(*i))))
156                 return -1;
157
158         i->be = be;
159         ast_copy_string(i->name, name, sizeof(i->name));
160         ast_copy_string(i->desc, desc, sizeof(i->desc));
161
162         AST_RWLIST_INSERT_HEAD(&be_list, i, list);
163         AST_RWLIST_UNLOCK(&be_list);
164
165         return 0;
166 }
167
168 /*! unregister a CDR driver */
169 void ast_cdr_unregister(const char *name)
170 {
171         struct ast_cdr_beitem *i = NULL;
172
173         AST_RWLIST_WRLOCK(&be_list);
174         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
175                 if (!strcasecmp(name, i->name)) {
176                         AST_RWLIST_REMOVE_CURRENT(list);
177                         break;
178                 }
179         }
180         AST_RWLIST_TRAVERSE_SAFE_END;
181         AST_RWLIST_UNLOCK(&be_list);
182
183         if (i) {
184                 ast_verb(2, "Unregistered '%s' CDR backend\n", name);
185                 ast_free(i);
186         }
187 }
188
189 int ast_cdr_isset_unanswered(void)
190 {
191         return unanswered;
192 }
193
194 int ast_cdr_isset_congestion(void)
195 {
196         return congestion;
197 }
198
199 struct ast_cdr *ast_cdr_dup_unique(struct ast_cdr *cdr)
200 {
201         struct ast_cdr *newcdr = ast_cdr_dup(cdr);
202         if (!newcdr)
203                 return NULL;
204
205         cdr_seq_inc(newcdr);
206         return newcdr;
207 }
208
209 struct ast_cdr *ast_cdr_dup_unique_swap(struct ast_cdr *cdr)
210 {
211         struct ast_cdr *newcdr = ast_cdr_dup(cdr);
212         if (!newcdr)
213                 return NULL;
214
215         cdr_seq_inc(cdr);
216         return newcdr;
217 }
218
219 /*! Duplicate a CDR record
220         \returns Pointer to new CDR record
221 */
222 struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr)
223 {
224         struct ast_cdr *newcdr;
225
226         if (!cdr) /* don't die if we get a null cdr pointer */
227                 return NULL;
228         newcdr = ast_cdr_alloc();
229         if (!newcdr)
230                 return NULL;
231
232         memcpy(newcdr, cdr, sizeof(*newcdr));
233         /* The varshead is unusable, volatile even, after the memcpy so we take care of that here */
234         memset(&newcdr->varshead, 0, sizeof(newcdr->varshead));
235         ast_cdr_copy_vars(newcdr, cdr);
236         newcdr->next = NULL;
237
238         return newcdr;
239 }
240
241 static const char *ast_cdr_getvar_internal(struct ast_cdr *cdr, const char *name, int recur)
242 {
243         if (ast_strlen_zero(name))
244                 return NULL;
245
246         for (; cdr; cdr = recur ? cdr->next : NULL) {
247                 struct ast_var_t *variables;
248                 struct varshead *headp = &cdr->varshead;
249                 AST_LIST_TRAVERSE(headp, variables, entries) {
250                         if (!strcasecmp(name, ast_var_name(variables)))
251                                 return ast_var_value(variables);
252                 }
253         }
254
255         return NULL;
256 }
257
258 static void cdr_get_tv(struct timeval when, const char *fmt, char *buf, int bufsize)
259 {
260         if (fmt == NULL) {      /* raw mode */
261                 snprintf(buf, bufsize, "%ld.%06ld", (long)when.tv_sec, (long)when.tv_usec);
262         } else {
263                 if (when.tv_sec) {
264                         struct ast_tm tm;
265
266                         ast_localtime(&when, &tm, NULL);
267                         ast_strftime(buf, bufsize, fmt, &tm);
268                 }
269         }
270 }
271
272 /*! CDR channel variable retrieval */
273 void ast_cdr_getvar(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int recur, int raw)
274 {
275         const char *fmt = "%Y-%m-%d %T";
276         const char *varbuf;
277
278         if (!cdr)  /* don't die if the cdr is null */
279                 return;
280
281         *ret = NULL;
282         /* special vars (the ones from the struct ast_cdr when requested by name)
283            I'd almost say we should convert all the stringed vals to vars */
284
285         if (!strcasecmp(name, "clid"))
286                 ast_copy_string(workspace, cdr->clid, workspacelen);
287         else if (!strcasecmp(name, "src"))
288                 ast_copy_string(workspace, cdr->src, workspacelen);
289         else if (!strcasecmp(name, "dst"))
290                 ast_copy_string(workspace, cdr->dst, workspacelen);
291         else if (!strcasecmp(name, "dcontext"))
292                 ast_copy_string(workspace, cdr->dcontext, workspacelen);
293         else if (!strcasecmp(name, "channel"))
294                 ast_copy_string(workspace, cdr->channel, workspacelen);
295         else if (!strcasecmp(name, "dstchannel"))
296                 ast_copy_string(workspace, cdr->dstchannel, workspacelen);
297         else if (!strcasecmp(name, "lastapp"))
298                 ast_copy_string(workspace, cdr->lastapp, workspacelen);
299         else if (!strcasecmp(name, "lastdata"))
300                 ast_copy_string(workspace, cdr->lastdata, workspacelen);
301         else if (!strcasecmp(name, "start"))
302                 cdr_get_tv(cdr->start, raw ? NULL : fmt, workspace, workspacelen);
303         else if (!strcasecmp(name, "answer"))
304                 cdr_get_tv(cdr->answer, raw ? NULL : fmt, workspace, workspacelen);
305         else if (!strcasecmp(name, "end"))
306                 cdr_get_tv(cdr->end, raw ? NULL : fmt, workspace, workspacelen);
307         else if (!strcasecmp(name, "duration")) {
308                 snprintf(workspace, workspacelen, "%ld", cdr->end.tv_sec != 0 ? cdr->duration : (long)ast_tvdiff_ms(ast_tvnow(), cdr->start) / 1000);
309         } else if (!strcasecmp(name, "billsec")) {
310                 snprintf(workspace, workspacelen, "%ld", (cdr->billsec || !ast_tvzero(cdr->end) || ast_tvzero(cdr->answer)) ? cdr->billsec : (long)ast_tvdiff_ms(ast_tvnow(), cdr->answer) / 1000);     
311         } else if (!strcasecmp(name, "disposition")) {
312                 if (raw) {
313                         snprintf(workspace, workspacelen, "%ld", cdr->disposition);
314                 } else {
315                         ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen);
316                 }
317         } else if (!strcasecmp(name, "amaflags")) {
318                 if (raw) {
319                         snprintf(workspace, workspacelen, "%ld", cdr->amaflags);
320                 } else {
321                         ast_copy_string(workspace, ast_cdr_flags2str(cdr->amaflags), workspacelen);
322                 }
323         } else if (!strcasecmp(name, "accountcode"))
324                 ast_copy_string(workspace, cdr->accountcode, workspacelen);
325         else if (!strcasecmp(name, "peeraccount"))
326                 ast_copy_string(workspace, cdr->peeraccount, workspacelen);
327         else if (!strcasecmp(name, "uniqueid"))
328                 ast_copy_string(workspace, cdr->uniqueid, workspacelen);
329         else if (!strcasecmp(name, "linkedid"))
330                 ast_copy_string(workspace, cdr->linkedid, workspacelen);
331         else if (!strcasecmp(name, "userfield"))
332                 ast_copy_string(workspace, cdr->userfield, workspacelen);
333         else if (!strcasecmp(name, "sequence"))
334                 snprintf(workspace, workspacelen, "%d", cdr->sequence);
335         else if ((varbuf = ast_cdr_getvar_internal(cdr, name, recur)))
336                 ast_copy_string(workspace, varbuf, workspacelen);
337         else
338                 workspace[0] = '\0';
339
340         if (!ast_strlen_zero(workspace))
341                 *ret = workspace;
342 }
343
344 /* readonly cdr variables */
345 static const char * const cdr_readonly_vars[] = { "clid", "src", "dst", "dcontext", "channel", "dstchannel",
346                                                   "lastapp", "lastdata", "start", "answer", "end", "duration",
347                                                   "billsec", "disposition", "amaflags", "accountcode", "uniqueid", "linkedid",
348                                                   "userfield", "sequence", NULL };
349 /*! Set a CDR channel variable
350         \note You can't set the CDR variables that belong to the actual CDR record, like "billsec".
351 */
352 int ast_cdr_setvar(struct ast_cdr *cdr, const char *name, const char *value, int recur)
353 {
354         struct ast_var_t *newvariable;
355         struct varshead *headp;
356         int x;
357
358         for (x = 0; cdr_readonly_vars[x]; x++) {
359                 if (!strcasecmp(name, cdr_readonly_vars[x])) {
360                         ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!.\n", name);
361                         return -1;
362                 }
363         }
364
365         if (!cdr) {
366                 ast_log(LOG_ERROR, "Attempt to set a variable on a nonexistent CDR record.\n");
367                 return -1;
368         }
369
370         for (; cdr; cdr = recur ? cdr->next : NULL) {
371                 if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
372                         continue;
373                 headp = &cdr->varshead;
374                 AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
375                         if (!strcasecmp(ast_var_name(newvariable), name)) {
376                                 /* there is already such a variable, delete it */
377                                 AST_LIST_REMOVE_CURRENT(entries);
378                                 ast_var_delete(newvariable);
379                                 break;
380                         }
381                 }
382                 AST_LIST_TRAVERSE_SAFE_END;
383
384                 if (value) {
385                         newvariable = ast_var_assign(name, value);
386                         AST_LIST_INSERT_HEAD(headp, newvariable, entries);
387                 }
388         }
389
390         return 0;
391 }
392
393 int ast_cdr_copy_vars(struct ast_cdr *to_cdr, struct ast_cdr *from_cdr)
394 {
395         struct ast_var_t *variables, *newvariable = NULL;
396         struct varshead *headpa, *headpb;
397         const char *var, *val;
398         int x = 0;
399
400         if (!to_cdr || !from_cdr) /* don't die if one of the pointers is null */
401                 return 0;
402
403         headpa = &from_cdr->varshead;
404         headpb = &to_cdr->varshead;
405
406         AST_LIST_TRAVERSE(headpa,variables,entries) {
407                 if (variables &&
408                     (var = ast_var_name(variables)) && (val = ast_var_value(variables)) &&
409                     !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
410                         newvariable = ast_var_assign(var, val);
411                         AST_LIST_INSERT_HEAD(headpb, newvariable, entries);
412                         x++;
413                 }
414         }
415
416         return x;
417 }
418
419 int ast_cdr_serialize_variables(struct ast_cdr *cdr, struct ast_str **buf, char delim, char sep, int recur)
420 {
421         struct ast_var_t *variables;
422         const char *var;
423         char *tmp;
424         char workspace[256];
425         int total = 0, x = 0, i;
426
427         ast_str_reset(*buf);
428
429         for (; cdr; cdr = recur ? cdr->next : NULL) {
430                 if (++x > 1)
431                         ast_str_append(buf, 0, "\n");
432
433                 AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) {
434                         if (!(var = ast_var_name(variables))) {
435                                 continue;
436                         }
437
438                         if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, var, delim, S_OR(ast_var_value(variables), ""), sep) < 0) {
439                                 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
440                                 break;
441                         }
442
443                         total++;
444                 }
445
446                 for (i = 0; cdr_readonly_vars[i]; i++) {
447                         workspace[0] = 0; /* null out the workspace, because the cdr_get_tv() won't write anything if time is NULL, so you get old vals */
448                         ast_cdr_getvar(cdr, cdr_readonly_vars[i], &tmp, workspace, sizeof(workspace), 0, 0);
449                         if (!tmp)
450                                 continue;
451
452                         if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, tmp, sep) < 0) {
453                                 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
454                                 break;
455                         } else
456                                 total++;
457                 }
458         }
459
460         return total;
461 }
462
463
464 void ast_cdr_free_vars(struct ast_cdr *cdr, int recur)
465 {
466
467         /* clear variables */
468         for (; cdr; cdr = recur ? cdr->next : NULL) {
469                 struct ast_var_t *vardata;
470                 struct varshead *headp = &cdr->varshead;
471                 while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
472                         ast_var_delete(vardata);
473         }
474 }
475
476 /*! \brief  print a warning if cdr already posted */
477 static void check_post(struct ast_cdr *cdr)
478 {
479         if (!cdr)
480                 return;
481         if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
482                 ast_log(LOG_NOTICE, "CDR on channel '%s' already posted\n", S_OR(cdr->channel, "<unknown>"));
483 }
484
485 void ast_cdr_free(struct ast_cdr *cdr)
486 {
487
488         while (cdr) {
489                 struct ast_cdr *next = cdr->next;
490
491                 ast_cdr_free_vars(cdr, 0);
492                 ast_free(cdr);
493                 cdr = next;
494         }
495 }
496
497 /*! \brief the same as a cdr_free call, only with no checks; just get rid of it */
498 void ast_cdr_discard(struct ast_cdr *cdr)
499 {
500         while (cdr) {
501                 struct ast_cdr *next = cdr->next;
502
503                 ast_cdr_free_vars(cdr, 0);
504                 ast_free(cdr);
505                 cdr = next;
506         }
507 }
508
509 struct ast_cdr *ast_cdr_alloc(void)
510 {
511         struct ast_cdr *x;
512         x = ast_calloc(1, sizeof(*x));
513         if (!x)
514                 ast_log(LOG_ERROR,"Allocation Failure for a CDR!\n");
515         return x;
516 }
517
518 static void cdr_merge_vars(struct ast_cdr *to, struct ast_cdr *from)
519 {
520         struct ast_var_t *variablesfrom,*variablesto;
521         struct varshead *headpfrom = &to->varshead;
522         struct varshead *headpto = &from->varshead;
523         AST_LIST_TRAVERSE_SAFE_BEGIN(headpfrom, variablesfrom, entries) {
524                 /* for every var in from, stick it in to */
525                 const char *fromvarname, *fromvarval;
526                 const char *tovarname = NULL, *tovarval = NULL;
527                 fromvarname = ast_var_name(variablesfrom);
528                 fromvarval = ast_var_value(variablesfrom);
529                 tovarname = 0;
530
531                 /* now, quick see if that var is in the 'to' cdr already */
532                 AST_LIST_TRAVERSE(headpto, variablesto, entries) {
533
534                         /* now, quick see if that var is in the 'to' cdr already */
535                         if ( strcasecmp(fromvarname, ast_var_name(variablesto)) == 0 ) {
536                                 tovarname = ast_var_name(variablesto);
537                                 tovarval = ast_var_value(variablesto);
538                                 break;
539                         }
540                 }
541                 if (tovarname && strcasecmp(fromvarval,tovarval) != 0) {  /* this message here to see how irritating the userbase finds it */
542                         ast_log(LOG_NOTICE, "Merging CDR's: variable %s value %s dropped in favor of value %s\n", tovarname, fromvarval, tovarval);
543                         continue;
544                 } else if (tovarname && strcasecmp(fromvarval,tovarval) == 0) /* if they are the same, the job is done */
545                         continue;
546
547                 /* rip this var out of the from cdr, and stick it in the to cdr */
548                 AST_LIST_MOVE_CURRENT(headpto, entries);
549         }
550         AST_LIST_TRAVERSE_SAFE_END;
551 }
552
553 void ast_cdr_merge(struct ast_cdr *to, struct ast_cdr *from)
554 {
555         struct ast_cdr *zcdr;
556         struct ast_cdr *lto = NULL;
557         struct ast_cdr *lfrom = NULL;
558         int discard_from = 0;
559
560         if (!to || !from)
561                 return;
562
563         /* don't merge into locked CDR's -- it's bad business */
564         if (ast_test_flag(to, AST_CDR_FLAG_LOCKED)) {
565                 zcdr = to; /* safety valve? */
566                 while (to->next) {
567                         lto = to;
568                         to = to->next;
569                 }
570
571                 if (ast_test_flag(to, AST_CDR_FLAG_LOCKED)) {
572                         ast_log(LOG_WARNING, "Merging into locked CDR... no choice.\n");
573                         to = zcdr; /* safety-- if all there are is locked CDR's, then.... ?? */
574                         lto = NULL;
575                 }
576         }
577
578         if (ast_test_flag(from, AST_CDR_FLAG_LOCKED)) {
579                 struct ast_cdr *llfrom = NULL;
580                 discard_from = 1;
581                 if (lto) {
582                         /* insert the from stuff after lto */
583                         lto->next = from;
584                         lfrom = from;
585                         while (lfrom && lfrom->next) {
586                                 if (!lfrom->next->next)
587                                         llfrom = lfrom;
588                                 lfrom = lfrom->next;
589                         }
590                         /* rip off the last entry and put a copy of the to at the end */
591                         if (llfrom) {
592                                 llfrom->next = to;
593                         }
594                         from = lfrom;
595                 } else {
596                         /* save copy of the current *to cdr */
597                         struct ast_cdr tcdr;
598                         memcpy(&tcdr, to, sizeof(tcdr));
599                         /* copy in the locked from cdr */
600                         memcpy(to, from, sizeof(*to));
601                         lfrom = from;
602                         while (lfrom && lfrom->next) {
603                                 if (!lfrom->next->next)
604                                         llfrom = lfrom;
605                                 lfrom = lfrom->next;
606                         }
607                         from->next = NULL;
608                         /* rip off the last entry and put a copy of the to at the end */
609                         if (llfrom == from) {
610                                 to = to->next = ast_cdr_dup(&tcdr);
611                         } else if (llfrom) {
612                                 to = llfrom->next = ast_cdr_dup(&tcdr);
613                         }
614                         from = lfrom;
615                 }
616         }
617
618         if (!ast_tvzero(from->start)) {
619                 if (!ast_tvzero(to->start)) {
620                         if (ast_tvcmp(to->start, from->start) > 0 ) {
621                                 to->start = from->start; /* use the earliest time */
622                                 from->start = ast_tv(0,0); /* we actively "steal" these values */
623                         }
624                         /* else nothing to do */
625                 } else {
626                         to->start = from->start;
627                         from->start = ast_tv(0,0); /* we actively "steal" these values */
628                 }
629         }
630         if (!ast_tvzero(from->answer)) {
631                 if (!ast_tvzero(to->answer)) {
632                         if (ast_tvcmp(to->answer, from->answer) > 0 ) {
633                                 to->answer = from->answer; /* use the earliest time */
634                                 from->answer = ast_tv(0,0); /* we actively "steal" these values */
635                         }
636                         /* we got the earliest answer time, so we'll settle for that? */
637                 } else {
638                         to->answer = from->answer;
639                         from->answer = ast_tv(0,0); /* we actively "steal" these values */
640                 }
641         }
642         if (!ast_tvzero(from->end)) {
643                 if (!ast_tvzero(to->end)) {
644                         if (ast_tvcmp(to->end, from->end) < 0 ) {
645                                 to->end = from->end; /* use the latest time */
646                                 from->end = ast_tv(0,0); /* we actively "steal" these values */
647                                 to->duration = to->end.tv_sec - to->start.tv_sec;  /* don't forget to update the duration, billsec, when we set end */
648                                 to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec;
649                         }
650                         /* else, nothing to do */
651                 } else {
652                         to->end = from->end;
653                         from->end = ast_tv(0,0); /* we actively "steal" these values */
654                         to->duration = to->end.tv_sec - to->start.tv_sec;
655                         to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec;
656                 }
657         }
658         if (to->disposition < from->disposition) {
659                 to->disposition = from->disposition;
660                 from->disposition = AST_CDR_NOANSWER;
661         }
662         if (ast_strlen_zero(to->lastapp) && !ast_strlen_zero(from->lastapp)) {
663                 ast_copy_string(to->lastapp, from->lastapp, sizeof(to->lastapp));
664                 from->lastapp[0] = 0; /* theft */
665         }
666         if (ast_strlen_zero(to->lastdata) && !ast_strlen_zero(from->lastdata)) {
667                 ast_copy_string(to->lastdata, from->lastdata, sizeof(to->lastdata));
668                 from->lastdata[0] = 0; /* theft */
669         }
670         if (ast_strlen_zero(to->dcontext) && !ast_strlen_zero(from->dcontext)) {
671                 ast_copy_string(to->dcontext, from->dcontext, sizeof(to->dcontext));
672                 from->dcontext[0] = 0; /* theft */
673         }
674         if (ast_strlen_zero(to->dstchannel) && !ast_strlen_zero(from->dstchannel)) {
675                 ast_copy_string(to->dstchannel, from->dstchannel, sizeof(to->dstchannel));
676                 from->dstchannel[0] = 0; /* theft */
677         }
678         if (!ast_strlen_zero(from->channel) && (ast_strlen_zero(to->channel) || !strncasecmp(from->channel, "Agent/", 6))) {
679                 ast_copy_string(to->channel, from->channel, sizeof(to->channel));
680                 from->channel[0] = 0; /* theft */
681         }
682         if (ast_strlen_zero(to->src) && !ast_strlen_zero(from->src)) {
683                 ast_copy_string(to->src, from->src, sizeof(to->src));
684                 from->src[0] = 0; /* theft */
685         }
686         if (ast_strlen_zero(to->clid) && !ast_strlen_zero(from->clid)) {
687                 ast_copy_string(to->clid, from->clid, sizeof(to->clid));
688                 from->clid[0] = 0; /* theft */
689         }
690         if (ast_strlen_zero(to->dst) && !ast_strlen_zero(from->dst)) {
691                 ast_copy_string(to->dst, from->dst, sizeof(to->dst));
692                 from->dst[0] = 0; /* theft */
693         }
694         if (!to->amaflags)
695                 to->amaflags = AST_CDR_DOCUMENTATION;
696         if (!from->amaflags)
697                 from->amaflags = AST_CDR_DOCUMENTATION; /* make sure both amaflags are set to something (DOC is default) */
698         if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (to->amaflags == AST_CDR_DOCUMENTATION && from->amaflags != AST_CDR_DOCUMENTATION)) {
699                 to->amaflags = from->amaflags;
700         }
701         if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->accountcode) && !ast_strlen_zero(from->accountcode))) {
702                 ast_copy_string(to->accountcode, from->accountcode, sizeof(to->accountcode));
703         }
704         if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->peeraccount) && !ast_strlen_zero(from->peeraccount))) {
705                 ast_copy_string(to->peeraccount, from->peeraccount, sizeof(to->peeraccount));
706         }
707         if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->userfield) && !ast_strlen_zero(from->userfield))) {
708                 ast_copy_string(to->userfield, from->userfield, sizeof(to->userfield));
709         }
710         /* flags, varsead, ? */
711         cdr_merge_vars(from, to);
712
713         if (ast_test_flag(from, AST_CDR_FLAG_KEEP_VARS))
714                 ast_set_flag(to, AST_CDR_FLAG_KEEP_VARS);
715         if (ast_test_flag(from, AST_CDR_FLAG_POSTED))
716                 ast_set_flag(to, AST_CDR_FLAG_POSTED);
717         if (ast_test_flag(from, AST_CDR_FLAG_LOCKED))
718                 ast_set_flag(to, AST_CDR_FLAG_LOCKED);
719         if (ast_test_flag(from, AST_CDR_FLAG_CHILD))
720                 ast_set_flag(to, AST_CDR_FLAG_CHILD);
721         if (ast_test_flag(from, AST_CDR_FLAG_POST_DISABLED))
722                 ast_set_flag(to, AST_CDR_FLAG_POST_DISABLED);
723
724         /* last, but not least, we need to merge any forked CDRs to the 'to' cdr */
725         while (from->next) {
726                 /* just rip 'em off the 'from' and insert them on the 'to' */
727                 zcdr = from->next;
728                 from->next = zcdr->next;
729                 zcdr->next = NULL;
730                 /* zcdr is now ripped from the current list; */
731                 ast_cdr_append(to, zcdr);
732         }
733         if (discard_from)
734                 ast_cdr_discard(from);
735 }
736
737 void ast_cdr_start(struct ast_cdr *cdr)
738 {
739         for (; cdr; cdr = cdr->next) {
740                 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
741                         check_post(cdr);
742                         cdr->start = ast_tvnow();
743                 }
744         }
745 }
746
747 void ast_cdr_answer(struct ast_cdr *cdr)
748 {
749
750         for (; cdr; cdr = cdr->next) {
751                 if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
752                         continue;
753                 if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
754                         continue;
755                 check_post(cdr);
756                 if (cdr->disposition < AST_CDR_ANSWERED)
757                         cdr->disposition = AST_CDR_ANSWERED;
758                 if (ast_tvzero(cdr->answer))
759                         cdr->answer = ast_tvnow();
760         }
761 }
762
763 void ast_cdr_busy(struct ast_cdr *cdr)
764 {
765
766         for (; cdr; cdr = cdr->next) {
767                 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
768                         check_post(cdr);
769                         cdr->disposition = AST_CDR_BUSY;
770                 }
771         }
772 }
773
774 void ast_cdr_failed(struct ast_cdr *cdr)
775 {
776         for (; cdr; cdr = cdr->next) {
777                 check_post(cdr);
778                 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
779                         check_post(cdr);
780                         if (cdr->disposition < AST_CDR_FAILED)
781                                 cdr->disposition = AST_CDR_FAILED;
782                 }
783         }
784 }
785
786 void ast_cdr_noanswer(struct ast_cdr *cdr)
787 {
788         while (cdr) {
789                 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
790                         check_post(cdr);
791                         cdr->disposition = AST_CDR_NOANSWER;
792                 }
793                 cdr = cdr->next;
794         }
795 }
796
797 void ast_cdr_congestion(struct ast_cdr *cdr)
798 {
799         char *chan;
800
801         /* if congestion log is disabled, pass the buck to ast_cdr_failed */
802         if (!congestion) {
803                 ast_cdr_failed(cdr);
804         }
805
806         while (cdr && congestion) {
807                 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
808                         chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
809
810                         if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED)) {
811                                 ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
812                         }
813
814                         if (cdr->disposition < AST_CDR_CONGESTION) {
815                                 cdr->disposition = AST_CDR_CONGESTION;
816                         }
817                 }
818                 cdr = cdr->next;
819         }
820 }
821
822 /* everywhere ast_cdr_disposition is called, it will call ast_cdr_failed()
823    if ast_cdr_disposition returns a non-zero value */
824
825 int ast_cdr_disposition(struct ast_cdr *cdr, int cause)
826 {
827         int res = 0;
828
829         for (; cdr; cdr = cdr->next) {
830                 switch (cause) {  /* handle all the non failure, busy cases, return 0 not to set disposition,
831                                                         return -1 to set disposition to FAILED */
832                 case AST_CAUSE_BUSY:
833                         ast_cdr_busy(cdr);
834                         break;
835                 case AST_CAUSE_NO_ANSWER:
836                         ast_cdr_noanswer(cdr);
837                         break;
838                 case AST_CAUSE_NORMAL_CIRCUIT_CONGESTION:
839                         ast_cdr_congestion(cdr);
840                         break;
841                 case AST_CAUSE_NORMAL:
842                         break;
843                 default:
844                         res = -1;
845                 }
846         }
847         return res;
848 }
849
850 void ast_cdr_setdestchan(struct ast_cdr *cdr, const char *chann)
851 {
852         for (; cdr; cdr = cdr->next) {
853                 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
854                         check_post(cdr);
855                         ast_copy_string(cdr->dstchannel, chann, sizeof(cdr->dstchannel));
856                 }
857         }
858 }
859
860 void ast_cdr_setapp(struct ast_cdr *cdr, const char *app, const char *data)
861 {
862
863         for (; cdr; cdr = cdr->next) {
864                 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
865                         check_post(cdr);
866                         ast_copy_string(cdr->lastapp, S_OR(app, ""), sizeof(cdr->lastapp));
867                         ast_copy_string(cdr->lastdata, S_OR(data, ""), sizeof(cdr->lastdata));
868                 }
869         }
870 }
871
872 void ast_cdr_setanswer(struct ast_cdr *cdr, struct timeval t)
873 {
874
875         for (; cdr; cdr = cdr->next) {
876                 if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
877                         continue;
878                 if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
879                         continue;
880                 check_post(cdr);
881                 cdr->answer = t;
882         }
883 }
884
885 void ast_cdr_setdisposition(struct ast_cdr *cdr, long int disposition)
886 {
887
888         for (; cdr; cdr = cdr->next) {
889                 if (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
890                         continue;
891                 check_post(cdr);
892                 cdr->disposition = disposition;
893         }
894 }
895
896 /* set cid info for one record */
897 static void set_one_cid(struct ast_cdr *cdr, struct ast_channel *c)
898 {
899         const char *num;
900
901         if (!cdr) {
902                 return;
903         }
904
905         /* Grab source from ANI or normal Caller*ID */
906         num = S_COR(ast_channel_caller(c)->ani.number.valid, ast_channel_caller(c)->ani.number.str,
907                 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL));
908         ast_callerid_merge(cdr->clid, sizeof(cdr->clid),
909                 S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, NULL), num, "");
910         ast_copy_string(cdr->src, S_OR(num, ""), sizeof(cdr->src));
911         ast_cdr_setvar(cdr, "dnid", S_OR(ast_channel_dialed(c)->number.str, ""), 0);
912
913         if (ast_channel_caller(c)->id.subaddress.valid) {
914                 ast_cdr_setvar(cdr, "callingsubaddr", S_OR(ast_channel_caller(c)->id.subaddress.str, ""), 0);
915         }
916         if (ast_channel_dialed(c)->subaddress.valid) {
917                 ast_cdr_setvar(cdr, "calledsubaddr", S_OR(ast_channel_dialed(c)->subaddress.str, ""), 0);
918         }
919 }
920
921 int ast_cdr_setcid(struct ast_cdr *cdr, struct ast_channel *c)
922 {
923         for (; cdr; cdr = cdr->next) {
924                 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
925                         set_one_cid(cdr, c);
926         }
927         return 0;
928 }
929
930 static int cdr_seq_inc(struct ast_cdr *cdr)
931 {
932         return (cdr->sequence = ast_atomic_fetchadd_int(&cdr_sequence, +1));
933 }
934
935 int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *c)
936 {
937         for ( ; cdr ; cdr = cdr->next) {
938                 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
939                         ast_copy_string(cdr->channel, ast_channel_name(c), sizeof(cdr->channel));
940                         set_one_cid(cdr, c);
941                         cdr_seq_inc(cdr);
942
943                         cdr->disposition = (ast_channel_state(c) == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NOANSWER;
944                         cdr->amaflags = ast_channel_amaflags(c) ? ast_channel_amaflags(c) :  ast_default_amaflags;
945                         ast_copy_string(cdr->accountcode, ast_channel_accountcode(c), sizeof(cdr->accountcode));
946                         ast_copy_string(cdr->peeraccount, ast_channel_peeraccount(c), sizeof(cdr->peeraccount));
947                         /* Destination information */
948                         ast_copy_string(cdr->dst, S_OR(ast_channel_macroexten(c),ast_channel_exten(c)), sizeof(cdr->dst));
949                         ast_copy_string(cdr->dcontext, S_OR(ast_channel_macrocontext(c),ast_channel_context(c)), sizeof(cdr->dcontext));
950                         /* Unique call identifier */
951                         ast_copy_string(cdr->uniqueid, ast_channel_uniqueid(c), sizeof(cdr->uniqueid));
952                         /* Linked call identifier */
953                         ast_copy_string(cdr->linkedid, ast_channel_linkedid(c), sizeof(cdr->linkedid));
954                 }
955         }
956         return 0;
957 }
958
959 /* Three routines were "fixed" via 10668, and later shown that
960    users were depending on this behavior. ast_cdr_end,
961    ast_cdr_setvar and ast_cdr_answer are the three routines.
962    While most of the other routines would not touch
963    LOCKED cdr's, these three routines were designed to
964    operate on locked CDR's as a matter of course.
965    I now appreciate how this plays with the ForkCDR app,
966    which forms these cdr chains in the first place.
967    cdr_end is pretty key: all cdrs created are closed
968    together. They only vary by start time. Arithmetically,
969    users can calculate the subintervals they wish to track. */
970
971 void ast_cdr_end(struct ast_cdr *cdr)
972 {
973         for ( ; cdr ; cdr = cdr->next) {
974                 if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
975                         continue;
976                 check_post(cdr);
977                 if (ast_tvzero(cdr->end))
978                         cdr->end = ast_tvnow();
979                 if (ast_tvzero(cdr->start)) {
980                         ast_log(LOG_WARNING, "CDR on channel '%s' has not started\n", S_OR(cdr->channel, "<unknown>"));
981                         cdr->disposition = AST_CDR_FAILED;
982                 } else
983                         cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec;
984                 if (ast_tvzero(cdr->answer)) {
985                         if (cdr->disposition == AST_CDR_ANSWERED) {
986                                 ast_log(LOG_WARNING, "CDR on channel '%s' has no answer time but is 'ANSWERED'\n", S_OR(cdr->channel, "<unknown>"));
987                                 cdr->disposition = AST_CDR_FAILED;
988                         }
989                 } else {
990                         cdr->billsec = cdr->end.tv_sec - cdr->answer.tv_sec;
991                         if (ast_test_flag(&ast_options, AST_OPT_FLAG_INITIATED_SECONDS))
992                                 cdr->billsec += cdr->end.tv_usec > cdr->answer.tv_usec ? 1 : 0;
993                 }
994         }
995 }
996
997 char *ast_cdr_disp2str(int disposition)
998 {
999         switch (disposition) {
1000         case AST_CDR_NULL:
1001                 return "NO ANSWER"; /* by default, for backward compatibility */
1002         case AST_CDR_NOANSWER:
1003                 return "NO ANSWER";
1004         case AST_CDR_FAILED:
1005                 return "FAILED";
1006         case AST_CDR_BUSY:
1007                 return "BUSY";
1008         case AST_CDR_ANSWERED:
1009                 return "ANSWERED";
1010         case AST_CDR_CONGESTION:
1011                 return "CONGESTION";
1012         }
1013         return "UNKNOWN";
1014 }
1015
1016 /*! Converts AMA flag to printable string 
1017  *
1018  * \param flag, flags
1019  */
1020 char *ast_cdr_flags2str(int flag)
1021 {
1022         switch (flag) {
1023         case AST_CDR_OMIT:
1024                 return "OMIT";
1025         case AST_CDR_BILLING:
1026                 return "BILLING";
1027         case AST_CDR_DOCUMENTATION:
1028                 return "DOCUMENTATION";
1029         }
1030         return "Unknown";
1031 }
1032
1033 int ast_cdr_setaccount(struct ast_channel *chan, const char *account)
1034 {
1035         struct ast_cdr *cdr = ast_channel_cdr(chan);
1036         const char *old_acct = "";
1037
1038         if (!ast_strlen_zero(ast_channel_accountcode(chan))) {
1039                 old_acct = ast_strdupa(ast_channel_accountcode(chan));
1040         }
1041
1042         ast_channel_accountcode_set(chan, account);
1043         for ( ; cdr ; cdr = cdr->next) {
1044                 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
1045                         ast_copy_string(cdr->accountcode, ast_channel_accountcode(chan), sizeof(cdr->accountcode));
1046                 }
1047         }
1048         /*** DOCUMENTATION
1049                 <managerEventInstance>
1050                         <synopsis>Raised when a CDR's AccountCode is changed.</synopsis>
1051                 </managerEventInstance>
1052         ***/
1053         ast_manager_event(chan, EVENT_FLAG_CALL, "NewAccountCode",
1054                         "Channel: %s\r\n"
1055                         "Uniqueid: %s\r\n"
1056                         "AccountCode: %s\r\n"
1057                         "OldAccountCode: %s\r\n",
1058                         ast_channel_name(chan), ast_channel_uniqueid(chan), ast_channel_accountcode(chan), old_acct);
1059
1060         return 0;
1061 }
1062
1063 int ast_cdr_setpeeraccount(struct ast_channel *chan, const char *account)
1064 {
1065         struct ast_cdr *cdr = ast_channel_cdr(chan);
1066         const char *old_acct = "";
1067
1068         if (!ast_strlen_zero(ast_channel_peeraccount(chan))) {
1069                 old_acct = ast_strdupa(ast_channel_peeraccount(chan));
1070         }
1071
1072         ast_channel_peeraccount_set(chan, account);
1073         for ( ; cdr ; cdr = cdr->next) {
1074                 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
1075                         ast_copy_string(cdr->peeraccount, ast_channel_peeraccount(chan), sizeof(cdr->peeraccount));
1076                 }
1077         }
1078         /*** DOCUMENTATION
1079                 <managerEventInstance>
1080                         <synopsis>Raised when a CDR's PeerAccount is changed.</synopsis>
1081                 </managerEventInstance>
1082         ***/
1083         ast_manager_event(chan, EVENT_FLAG_CALL, "NewPeerAccount",
1084                         "Channel: %s\r\n"
1085                         "Uniqueid: %s\r\n"
1086                         "PeerAccount: %s\r\n"
1087                         "OldPeerAccount: %s\r\n",
1088                         ast_channel_name(chan), ast_channel_uniqueid(chan), ast_channel_peeraccount(chan), old_acct);
1089
1090         return 0;
1091 }
1092
1093 int ast_cdr_setamaflags(struct ast_channel *chan, const char *flag)
1094 {
1095         struct ast_cdr *cdr;
1096         int newflag = ast_cdr_amaflags2int(flag);
1097         if (newflag) {
1098                 for (cdr = ast_channel_cdr(chan); cdr; cdr = cdr->next) {
1099                         if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
1100                                 cdr->amaflags = newflag;
1101                         }
1102                 }
1103         }
1104
1105         return 0;
1106 }
1107
1108 int ast_cdr_setuserfield(struct ast_channel *chan, const char *userfield)
1109 {
1110         struct ast_cdr *cdr = ast_channel_cdr(chan);
1111
1112         for ( ; cdr ; cdr = cdr->next) {
1113                 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
1114                         ast_copy_string(cdr->userfield, userfield, sizeof(cdr->userfield));
1115         }
1116
1117         return 0;
1118 }
1119
1120 int ast_cdr_appenduserfield(struct ast_channel *chan, const char *userfield)
1121 {
1122         struct ast_cdr *cdr = ast_channel_cdr(chan);
1123
1124         for ( ; cdr ; cdr = cdr->next) {
1125                 int len = strlen(cdr->userfield);
1126
1127                 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
1128                         ast_copy_string(cdr->userfield + len, userfield, sizeof(cdr->userfield) - len);
1129         }
1130
1131         return 0;
1132 }
1133
1134 int ast_cdr_update(struct ast_channel *c)
1135 {
1136         struct ast_cdr *cdr = ast_channel_cdr(c);
1137
1138         for ( ; cdr ; cdr = cdr->next) {
1139                 if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
1140                         set_one_cid(cdr, c);
1141
1142                         /* Copy account code et-al */
1143                         ast_copy_string(cdr->accountcode, ast_channel_accountcode(c), sizeof(cdr->accountcode));
1144                         ast_copy_string(cdr->peeraccount, ast_channel_peeraccount(c), sizeof(cdr->peeraccount));
1145                         ast_copy_string(cdr->linkedid, ast_channel_linkedid(c), sizeof(cdr->linkedid));
1146
1147                         /* Destination information */ /* XXX privilege macro* ? */
1148                         ast_copy_string(cdr->dst, S_OR(ast_channel_macroexten(c), ast_channel_exten(c)), sizeof(cdr->dst));
1149                         ast_copy_string(cdr->dcontext, S_OR(ast_channel_macrocontext(c), ast_channel_context(c)), sizeof(cdr->dcontext));
1150                 }
1151         }
1152
1153         return 0;
1154 }
1155
1156 int ast_cdr_amaflags2int(const char *flag)
1157 {
1158         if (!strcasecmp(flag, "default"))
1159                 return 0;
1160         if (!strcasecmp(flag, "omit"))
1161                 return AST_CDR_OMIT;
1162         if (!strcasecmp(flag, "billing"))
1163                 return AST_CDR_BILLING;
1164         if (!strcasecmp(flag, "documentation"))
1165                 return AST_CDR_DOCUMENTATION;
1166         return -1;
1167 }
1168
1169 static void post_cdr(struct ast_cdr *cdr)
1170 {
1171         struct ast_cdr_beitem *i;
1172
1173         for ( ; cdr ; cdr = cdr->next) {
1174                 if (!unanswered && cdr->disposition < AST_CDR_ANSWERED && (ast_strlen_zero(cdr->channel) || ast_strlen_zero(cdr->dstchannel))) {
1175                         /* For people, who don't want to see unanswered single-channel events */
1176                         ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
1177                         continue;
1178                 }
1179
1180                 /* don't post CDRs that are for dialed channels unless those
1181                  * channels were originated from asterisk (pbx_spool, manager,
1182                  * cli) */
1183                 if (ast_test_flag(cdr, AST_CDR_FLAG_DIALED) && !ast_test_flag(cdr, AST_CDR_FLAG_ORIGINATED)) {
1184                         ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
1185                         continue;
1186                 }
1187
1188                 check_post(cdr);
1189                 ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
1190                 if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED))
1191                         continue;
1192                 AST_RWLIST_RDLOCK(&be_list);
1193                 AST_RWLIST_TRAVERSE(&be_list, i, list) {
1194                         i->be(cdr);
1195                 }
1196                 AST_RWLIST_UNLOCK(&be_list);
1197         }
1198 }
1199
1200 void ast_cdr_reset(struct ast_cdr *cdr, struct ast_flags *_flags)
1201 {
1202         struct ast_cdr *duplicate;
1203         struct ast_flags flags = { 0 };
1204
1205         if (_flags)
1206                 ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
1207
1208         for ( ; cdr ; cdr = cdr->next) {
1209                 /* Detach if post is requested */
1210                 if (ast_test_flag(&flags, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
1211                         if (ast_test_flag(&flags, AST_CDR_FLAG_POSTED)) {
1212                                 ast_cdr_end(cdr);
1213                                 if ((duplicate = ast_cdr_dup_unique_swap(cdr))) {
1214                                         ast_cdr_detach(duplicate);
1215                                 }
1216                                 ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
1217                         }
1218
1219                         /* enable CDR only */
1220                         if (ast_test_flag(&flags, AST_CDR_FLAG_POST_ENABLE)) {
1221                                 ast_clear_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
1222                                 continue;
1223                         }
1224
1225                         /* clear variables */
1226                         if (!ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) {
1227                                 ast_cdr_free_vars(cdr, 0);
1228                         }
1229
1230                         /* Reset to initial state */
1231                         ast_clear_flag(cdr, AST_FLAGS_ALL);
1232                         memset(&cdr->start, 0, sizeof(cdr->start));
1233                         memset(&cdr->end, 0, sizeof(cdr->end));
1234                         memset(&cdr->answer, 0, sizeof(cdr->answer));
1235                         cdr->billsec = 0;
1236                         cdr->duration = 0;
1237                         ast_cdr_start(cdr);
1238                         cdr->disposition = AST_CDR_NOANSWER;
1239                 }
1240         }
1241 }
1242
1243 void ast_cdr_specialized_reset(struct ast_cdr *cdr, struct ast_flags *_flags)
1244 {
1245         struct ast_flags flags = { 0 };
1246
1247         if (_flags)
1248                 ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
1249
1250         /* Reset to initial state */
1251         if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED)) { /* But do NOT lose the NoCDR() setting */
1252                 ast_clear_flag(cdr, AST_FLAGS_ALL);
1253                 ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
1254         } else {
1255                 ast_clear_flag(cdr, AST_FLAGS_ALL);
1256         }
1257
1258         memset(&cdr->start, 0, sizeof(cdr->start));
1259         memset(&cdr->end, 0, sizeof(cdr->end));
1260         memset(&cdr->answer, 0, sizeof(cdr->answer));
1261         cdr->billsec = 0;
1262         cdr->duration = 0;
1263         ast_cdr_start(cdr);
1264         cdr->disposition = AST_CDR_NULL;
1265 }
1266
1267 struct ast_cdr *ast_cdr_append(struct ast_cdr *cdr, struct ast_cdr *newcdr)
1268 {
1269         struct ast_cdr *ret;
1270
1271         if (cdr) {
1272                 ret = cdr;
1273
1274                 while (cdr->next)
1275                         cdr = cdr->next;
1276                 cdr->next = newcdr;
1277         } else {
1278                 ret = newcdr;
1279         }
1280
1281         return ret;
1282 }
1283
1284 /*! \note Don't call without cdr_batch_lock */
1285 static void reset_batch(void)
1286 {
1287         batch->size = 0;
1288         batch->head = NULL;
1289         batch->tail = NULL;
1290 }
1291
1292 /*! \note Don't call without cdr_batch_lock */
1293 static int init_batch(void)
1294 {
1295         /* This is the single meta-batch used to keep track of all CDRs during the entire life of the program */
1296         if (!(batch = ast_malloc(sizeof(*batch))))
1297                 return -1;
1298
1299         reset_batch();
1300
1301         return 0;
1302 }
1303
1304 static void *do_batch_backend_process(void *data)
1305 {
1306         struct ast_cdr_batch_item *processeditem;
1307         struct ast_cdr_batch_item *batchitem = data;
1308
1309         /* Push each CDR into storage mechanism(s) and free all the memory */
1310         while (batchitem) {
1311                 post_cdr(batchitem->cdr);
1312                 ast_cdr_free(batchitem->cdr);
1313                 processeditem = batchitem;
1314                 batchitem = batchitem->next;
1315                 ast_free(processeditem);
1316         }
1317
1318         return NULL;
1319 }
1320
1321 void ast_cdr_submit_batch(int do_shutdown)
1322 {
1323         struct ast_cdr_batch_item *oldbatchitems = NULL;
1324         pthread_t batch_post_thread = AST_PTHREADT_NULL;
1325
1326         /* if there's no batch, or no CDRs in the batch, then there's nothing to do */
1327         if (!batch || !batch->head)
1328                 return;
1329
1330         /* move the old CDRs aside, and prepare a new CDR batch */
1331         ast_mutex_lock(&cdr_batch_lock);
1332         oldbatchitems = batch->head;
1333         reset_batch();
1334         ast_mutex_unlock(&cdr_batch_lock);
1335
1336         /* if configured, spawn a new thread to post these CDRs,
1337            also try to save as much as possible if we are shutting down safely */
1338         if (batchscheduleronly || do_shutdown) {
1339                 ast_debug(1, "CDR single-threaded batch processing begins now\n");
1340                 do_batch_backend_process(oldbatchitems);
1341         } else {
1342                 if (ast_pthread_create_detached_background(&batch_post_thread, NULL, do_batch_backend_process, oldbatchitems)) {
1343                         ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n");
1344                         do_batch_backend_process(oldbatchitems);
1345                 } else {
1346                         ast_debug(1, "CDR multi-threaded batch processing begins now\n");
1347                 }
1348         }
1349 }
1350
1351 static int submit_scheduled_batch(const void *data)
1352 {
1353         ast_cdr_submit_batch(0);
1354         /* manually reschedule from this point in time */
1355         cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
1356         /* returning zero so the scheduler does not automatically reschedule */
1357         return 0;
1358 }
1359
1360 static void submit_unscheduled_batch(void)
1361 {
1362         /* this is okay since we are not being called from within the scheduler */
1363         AST_SCHED_DEL(sched, cdr_sched);
1364         /* schedule the submission to occur ASAP (1 ms) */
1365         cdr_sched = ast_sched_add(sched, 1, submit_scheduled_batch, NULL);
1366         /* signal the do_cdr thread to wakeup early and do some work (that lazy thread ;) */
1367         ast_mutex_lock(&cdr_pending_lock);
1368         ast_cond_signal(&cdr_pending_cond);
1369         ast_mutex_unlock(&cdr_pending_lock);
1370 }
1371
1372 void ast_cdr_detach(struct ast_cdr *cdr)
1373 {
1374         struct ast_cdr_batch_item *newtail;
1375         int curr;
1376
1377         if (!cdr)
1378                 return;
1379
1380         /* maybe they disabled CDR stuff completely, so just drop it */
1381         if (!enabled) {
1382                 ast_debug(1, "Dropping CDR !\n");
1383                 ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
1384                 ast_cdr_free(cdr);
1385                 return;
1386         }
1387
1388         /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
1389         if (!batchmode) {
1390                 post_cdr(cdr);
1391                 ast_cdr_free(cdr);
1392                 return;
1393         }
1394
1395         /* otherwise, each CDR gets put into a batch list (at the end) */
1396         ast_debug(1, "CDR detaching from this thread\n");
1397
1398         /* we'll need a new tail for every CDR */
1399         if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
1400                 post_cdr(cdr);
1401                 ast_cdr_free(cdr);
1402                 return;
1403         }
1404
1405         /* don't traverse a whole list (just keep track of the tail) */
1406         ast_mutex_lock(&cdr_batch_lock);
1407         if (!batch)
1408                 init_batch();
1409         if (!batch->head) {
1410                 /* new batch is empty, so point the head at the new tail */
1411                 batch->head = newtail;
1412         } else {
1413                 /* already got a batch with something in it, so just append a new tail */
1414                 batch->tail->next = newtail;
1415         }
1416         newtail->cdr = cdr;
1417         batch->tail = newtail;
1418         curr = batch->size++;
1419         ast_mutex_unlock(&cdr_batch_lock);
1420
1421         /* if we have enough stuff to post, then do it */
1422         if (curr >= (batchsize - 1))
1423                 submit_unscheduled_batch();
1424 }
1425
1426 static void *do_cdr(void *data)
1427 {
1428         struct timespec timeout;
1429         int schedms;
1430         int numevents = 0;
1431
1432         for (;;) {
1433                 struct timeval now;
1434                 schedms = ast_sched_wait(sched);
1435                 /* this shouldn't happen, but provide a 1 second default just in case */
1436                 if (schedms <= 0)
1437                         schedms = 1000;
1438                 now = ast_tvadd(ast_tvnow(), ast_samp2tv(schedms, 1000));
1439                 timeout.tv_sec = now.tv_sec;
1440                 timeout.tv_nsec = now.tv_usec * 1000;
1441                 /* prevent stuff from clobbering cdr_pending_cond, then wait on signals sent to it until the timeout expires */
1442                 ast_mutex_lock(&cdr_pending_lock);
1443                 ast_cond_timedwait(&cdr_pending_cond, &cdr_pending_lock, &timeout);
1444                 numevents = ast_sched_runq(sched);
1445                 ast_mutex_unlock(&cdr_pending_lock);
1446                 ast_debug(2, "Processed %d scheduled CDR batches from the run queue\n", numevents);
1447         }
1448
1449         return NULL;
1450 }
1451
1452 static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1453 {
1454         struct ast_cdr_beitem *beitem=NULL;
1455         int cnt=0;
1456         long nextbatchtime=0;
1457
1458         switch (cmd) {
1459         case CLI_INIT:
1460                 e->command = "cdr show status";
1461                 e->usage =
1462                         "Usage: cdr show status\n"
1463                         "       Displays the Call Detail Record engine system status.\n";
1464                 return NULL;
1465         case CLI_GENERATE:
1466                 return NULL;
1467         }
1468
1469         if (a->argc > 3)
1470                 return CLI_SHOWUSAGE;
1471
1472         ast_cli(a->fd, "\n");
1473         ast_cli(a->fd, "Call Detail Record (CDR) settings\n");
1474         ast_cli(a->fd, "----------------------------------\n");
1475         ast_cli(a->fd, "  Logging:                    %s\n", enabled ? "Enabled" : "Disabled");
1476         ast_cli(a->fd, "  Mode:                       %s\n", batchmode ? "Batch" : "Simple");
1477         if (enabled) {
1478                 ast_cli(a->fd, "  Log unanswered calls:       %s\n", unanswered ? "Yes" : "No");
1479                 ast_cli(a->fd, "  Log congestion:             %s\n\n", congestion ? "Yes" : "No");
1480                 if (batchmode) {
1481                         ast_cli(a->fd, "* Batch Mode Settings\n");
1482                         ast_cli(a->fd, "  -------------------\n");
1483                         if (batch)
1484                                 cnt = batch->size;
1485                         if (cdr_sched > -1)
1486                                 nextbatchtime = ast_sched_when(sched, cdr_sched);
1487                         ast_cli(a->fd, "  Safe shutdown:              %s\n", batchsafeshutdown ? "Enabled" : "Disabled");
1488                         ast_cli(a->fd, "  Threading model:            %s\n", batchscheduleronly ? "Scheduler only" : "Scheduler plus separate threads");
1489                         ast_cli(a->fd, "  Current batch size:         %d record%s\n", cnt, ESS(cnt));
1490                         ast_cli(a->fd, "  Maximum batch size:         %d record%s\n", batchsize, ESS(batchsize));
1491                         ast_cli(a->fd, "  Maximum batch time:         %d second%s\n", batchtime, ESS(batchtime));
1492                         ast_cli(a->fd, "  Next batch processing time: %ld second%s\n\n", nextbatchtime, ESS(nextbatchtime));
1493                 }
1494                 ast_cli(a->fd, "* Registered Backends\n");
1495                 ast_cli(a->fd, "  -------------------\n");
1496                 AST_RWLIST_RDLOCK(&be_list);
1497                 if (AST_RWLIST_EMPTY(&be_list)) {
1498                         ast_cli(a->fd, "    (none)\n");
1499                 } else {
1500                         AST_RWLIST_TRAVERSE(&be_list, beitem, list) {
1501                                 ast_cli(a->fd, "    %s\n", beitem->name);
1502                         }
1503                 }
1504                 AST_RWLIST_UNLOCK(&be_list);
1505                 ast_cli(a->fd, "\n");
1506         }
1507
1508         return CLI_SUCCESS;
1509 }
1510
1511 static char *handle_cli_submit(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1512 {
1513         switch (cmd) {
1514         case CLI_INIT:
1515                 e->command = "cdr submit";
1516                 e->usage =
1517                         "Usage: cdr submit\n"
1518                         "       Posts all pending batched CDR data to the configured CDR backend engine modules.\n";
1519                 return NULL;
1520         case CLI_GENERATE:
1521                 return NULL;
1522         }
1523         if (a->argc > 2)
1524                 return CLI_SHOWUSAGE;
1525
1526         submit_unscheduled_batch();
1527         ast_cli(a->fd, "Submitted CDRs to backend engines for processing.  This may take a while.\n");
1528
1529         return CLI_SUCCESS;
1530 }
1531
1532 static struct ast_cli_entry cli_submit = AST_CLI_DEFINE(handle_cli_submit, "Posts all pending batched CDR data");
1533 static struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CDR status");
1534
1535 static int do_reload(int reload)
1536 {
1537         struct ast_config *config;
1538         struct ast_variable *v;
1539         int cfg_size;
1540         int cfg_time;
1541         int was_enabled;
1542         int was_batchmode;
1543         int res = 0;
1544         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1545
1546         if ((config = ast_config_load2("cdr.conf", "cdr", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
1547                 return 0;
1548         }
1549
1550         ast_mutex_lock(&cdr_batch_lock);
1551
1552         was_enabled = enabled;
1553         was_batchmode = batchmode;
1554
1555         batchsize = BATCH_SIZE_DEFAULT;
1556         batchtime = BATCH_TIME_DEFAULT;
1557         batchscheduleronly = BATCH_SCHEDULER_ONLY_DEFAULT;
1558         batchsafeshutdown = BATCH_SAFE_SHUTDOWN_DEFAULT;
1559         enabled = ENABLED_DEFAULT;
1560         batchmode = BATCHMODE_DEFAULT;
1561         unanswered = UNANSWERED_DEFAULT;
1562         congestion = CONGESTION_DEFAULT;
1563
1564         if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
1565                 ast_mutex_unlock(&cdr_batch_lock);
1566                 return 0;
1567         }
1568
1569         /* don't run the next scheduled CDR posting while reloading */
1570         AST_SCHED_DEL(sched, cdr_sched);
1571
1572         for (v = ast_variable_browse(config, "general"); v; v = v->next) {
1573                 if (!strcasecmp(v->name, "enable")) {
1574                         enabled = ast_true(v->value);
1575                 } else if (!strcasecmp(v->name, "unanswered")) {
1576                         unanswered = ast_true(v->value);
1577                 } else if (!strcasecmp(v->name, "congestion")) {
1578                         congestion = ast_true(v->value);
1579                 } else if (!strcasecmp(v->name, "batch")) {
1580                         batchmode = ast_true(v->value);
1581                 } else if (!strcasecmp(v->name, "scheduleronly")) {
1582                         batchscheduleronly = ast_true(v->value);
1583                 } else if (!strcasecmp(v->name, "safeshutdown")) {
1584                         batchsafeshutdown = ast_true(v->value);
1585                 } else if (!strcasecmp(v->name, "size")) {
1586                         if (sscanf(v->value, "%30d", &cfg_size) < 1) {
1587                                 ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", v->value);
1588                         } else if (cfg_size < 0) {
1589                                 ast_log(LOG_WARNING, "Invalid maximum batch size '%d' specified, using default\n", cfg_size);
1590                         } else {
1591                                 batchsize = cfg_size;
1592                         }
1593                 } else if (!strcasecmp(v->name, "time")) {
1594                         if (sscanf(v->value, "%30d", &cfg_time) < 1) {
1595                                 ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", v->value);
1596                         } else if (cfg_time < 0) {
1597                                 ast_log(LOG_WARNING, "Invalid maximum batch time '%d' specified, using default\n", cfg_time);
1598                         } else {
1599                                 batchtime = cfg_time;
1600                         }
1601                 } else if (!strcasecmp(v->name, "endbeforehexten")) {
1602                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN);
1603                 } else if (!strcasecmp(v->name, "initiatedseconds")) {
1604                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INITIATED_SECONDS);
1605                 }
1606         }
1607
1608         if (enabled && !batchmode) {
1609                 ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
1610         } else if (enabled && batchmode) {
1611                 cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
1612                 ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %d or time %d seconds.\n", batchsize, batchtime);
1613         } else {
1614                 ast_log(LOG_NOTICE, "CDR logging disabled, data will be lost.\n");
1615         }
1616
1617         /* if this reload enabled the CDR batch mode, create the background thread
1618            if it does not exist */
1619         if (enabled && batchmode && (!was_enabled || !was_batchmode) && (cdr_thread == AST_PTHREADT_NULL)) {
1620                 ast_cond_init(&cdr_pending_cond, NULL);
1621                 if (ast_pthread_create_background(&cdr_thread, NULL, do_cdr, NULL) < 0) {
1622                         ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
1623                         AST_SCHED_DEL(sched, cdr_sched);
1624                 } else {
1625                         ast_cli_register(&cli_submit);
1626                         ast_register_atexit(ast_cdr_engine_term);
1627                         res = 0;
1628                 }
1629         /* if this reload disabled the CDR and/or batch mode and there is a background thread,
1630            kill it */
1631         } else if (((!enabled && was_enabled) || (!batchmode && was_batchmode)) && (cdr_thread != AST_PTHREADT_NULL)) {
1632                 /* wake up the thread so it will exit */
1633                 pthread_cancel(cdr_thread);
1634                 pthread_kill(cdr_thread, SIGURG);
1635                 pthread_join(cdr_thread, NULL);
1636                 cdr_thread = AST_PTHREADT_NULL;
1637                 ast_cond_destroy(&cdr_pending_cond);
1638                 ast_cli_unregister(&cli_submit);
1639                 ast_unregister_atexit(ast_cdr_engine_term);
1640                 res = 0;
1641                 /* if leaving batch mode, then post the CDRs in the batch,
1642                    and don't reschedule, since we are stopping CDR logging */
1643                 if (!batchmode && was_batchmode) {
1644                         ast_cdr_engine_term();
1645                 }
1646         } else {
1647                 res = 0;
1648         }
1649
1650         ast_mutex_unlock(&cdr_batch_lock);
1651         ast_config_destroy(config);
1652         manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: CDR\r\nMessage: CDR subsystem reload requested\r\n");
1653
1654         return res;
1655 }
1656
1657 int ast_cdr_engine_init(void)
1658 {
1659         int res;
1660
1661         sched = ast_sched_context_create();
1662         if (!sched) {
1663                 ast_log(LOG_ERROR, "Unable to create schedule context.\n");
1664                 return -1;
1665         }
1666
1667         ast_cli_register(&cli_status);
1668
1669         res = do_reload(0);
1670         if (res) {
1671                 ast_mutex_lock(&cdr_batch_lock);
1672                 res = init_batch();
1673                 ast_mutex_unlock(&cdr_batch_lock);
1674         }
1675
1676         return res;
1677 }
1678
1679 /* \note This actually gets called a couple of times at shutdown.  Once, before we start
1680    hanging up channels, and then again, after the channel hangup timeout expires */
1681 void ast_cdr_engine_term(void)
1682 {
1683         ast_cdr_submit_batch(batchsafeshutdown);
1684 }
1685
1686 int ast_cdr_engine_reload(void)
1687 {
1688         return do_reload(1);
1689 }
1690
1691 int ast_cdr_data_add_structure(struct ast_data *tree, struct ast_cdr *cdr, int recur)
1692 {
1693         struct ast_cdr *tmpcdr;
1694         struct ast_data *level;
1695         struct ast_var_t *variables;
1696         const char *var, *val;
1697         int x = 1, i;
1698         char workspace[256];
1699         char *tmp;
1700
1701         if (!cdr) {
1702                 return -1;
1703         }
1704
1705         for (tmpcdr = cdr; tmpcdr; tmpcdr = (recur ? tmpcdr->next : NULL)) {
1706                 level = ast_data_add_node(tree, "level");
1707                 if (!level) {
1708                         continue;
1709                 }
1710
1711                 ast_data_add_int(level, "level_number", x);
1712
1713                 AST_LIST_TRAVERSE(&tmpcdr->varshead, variables, entries) {
1714                         if (variables && (var = ast_var_name(variables)) &&
1715                                         (val = ast_var_value(variables)) && !ast_strlen_zero(var)
1716                                         && !ast_strlen_zero(val)) {
1717                                 ast_data_add_str(level, var, val);
1718                         } else {
1719                                 break;
1720                         }
1721                 }
1722
1723                 for (i = 0; cdr_readonly_vars[i]; i++) {
1724                         workspace[0] = 0; /* null out the workspace, because the cdr_get_tv() won't write anything if time is NULL, so you get old vals */
1725                         ast_cdr_getvar(tmpcdr, cdr_readonly_vars[i], &tmp, workspace, sizeof(workspace), 0, 0);
1726                         if (!tmp) {
1727                                 continue;
1728                         }
1729                         ast_data_add_str(level, cdr_readonly_vars[i], tmp);
1730                 }
1731
1732                 x++;
1733         }
1734
1735         return 0;
1736 }
1737