8d01a829c4d7740d111054bcea9ea031738f09e3
[asterisk/asterisk.git] / apps / app_forkcdr.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Anthony Minessale anthmct@yahoo.com
5  * Development of this app Sponsered/Funded  by TAAN Softworks Corp
6  *
7  * See http://www.asterisk.org for more information about
8  * the Asterisk project. Please do not directly contact
9  * any of the maintainers of this project for assistance;
10  * the project provides a web site, mailing lists and IRC
11  * channels for your use.
12  *
13  * This program is free software, distributed under the terms of
14  * the GNU General Public License Version 2. See the LICENSE file
15  * at the top of the source tree.
16  */
17
18 /*! \file
19  *
20  * \brief Fork CDR application
21  *
22  * \author Anthony Minessale anthmct@yahoo.com
23  *
24  * \note Development of this app Sponsored/Funded by TAAN Softworks Corp
25  * 
26  * \ingroup applications
27  */
28
29 #include "asterisk.h"
30
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32
33 #include "asterisk/file.h"
34 #include "asterisk/channel.h"
35 #include "asterisk/pbx.h"
36 #include "asterisk/cdr.h"
37 #include "asterisk/app.h"
38 #include "asterisk/module.h"
39
40 static char *app = "ForkCDR";
41 static char *synopsis = 
42 "Forks the Call Data Record";
43 static char *descrip = 
44 "  ForkCDR([options]):  Causes the Call Data Record to fork an additional\n"
45 "cdr record starting from the time of the fork call\n"
46 "  Options:\n"
47 "    a  - update the answer time on the NEW CDR just after it's been inited..\n"
48 "         The new CDR may have been answered already, the reset that forkcdr.\n"
49 "         does will erase the answer time. This will bring it back, but.\n"
50 "         the answer time will be a copy of the fork/start time. It will.\n"
51 "         only do this if the initial cdr was indeed already answered..\n"
52 "    D -  Copy the disposition forward from the old cdr, after the .\n"
53 "         init..\n"
54 "    d -  Clear the dstchannel on the new CDR after reset..\n"
55 "    e -  end the original CDR. Do this after all the necc. data.\n"
56 "         is copied from the original CDR to the new forked CDR..\n"
57 "    R -  do NOT reset the new cdr..\n"
58 "    s(name=val) - Set the CDR var 'name' in the original CDR, with value.\n"
59 "                  'val'.\n"
60 "    v  - When the new CDR is forked, it gets a copy of the vars attached\n"
61 "         to the current CDR. The vars attached to the original CDR are removed\n"
62 "         unless this option is specified.\n";
63
64
65 enum {
66         OPT_SETANS =            (1 << 0),
67         OPT_SETDISP =           (1 << 1),
68         OPT_RESETDEST =         (1 << 2),
69         OPT_ENDCDR =            (1 << 3),
70         OPT_NORESET =           (1 << 4),
71         OPT_KEEPVARS =          (1 << 5),
72         OPT_VARSET =            (1 << 6),
73 };
74
75 enum {
76         OPT_ARG_VARSET = 0,
77         /* note: this entry _MUST_ be the last one in the enum */
78         OPT_ARG_ARRAY_SIZE,
79 };
80
81 AST_APP_OPTIONS(forkcdr_exec_options, {
82         AST_APP_OPTION('a', OPT_SETANS),
83         AST_APP_OPTION('d', OPT_SETDISP),
84         AST_APP_OPTION('D', OPT_RESETDEST),
85         AST_APP_OPTION('e', OPT_ENDCDR),
86         AST_APP_OPTION('R', OPT_NORESET),
87         AST_APP_OPTION_ARG('s', OPT_VARSET, OPT_ARG_VARSET),
88         AST_APP_OPTION('v', OPT_KEEPVARS),
89 });
90
91 static void ast_cdr_fork(struct ast_channel *chan, struct ast_flags optflags, char *set) 
92 {
93         struct ast_cdr *cdr;
94         struct ast_cdr *newcdr;
95         struct ast_flags flags = { AST_CDR_FLAG_KEEP_VARS };
96
97         cdr = chan->cdr;
98
99         while (cdr->next)
100                 cdr = cdr->next;
101         
102         if (!(newcdr = ast_cdr_dup(cdr)))
103                 return;
104         
105         ast_cdr_append(cdr, newcdr);
106
107         if (!ast_test_flag(&optflags, OPT_NORESET))
108                 ast_cdr_reset(newcdr, &flags);
109                 
110         if (!ast_test_flag(cdr, AST_CDR_FLAG_KEEP_VARS))
111                 ast_cdr_free_vars(cdr, 0);
112         
113         if (!ast_strlen_zero(set)) {
114                 char *varname = ast_strdupa(set), *varval;
115                 varval = strchr(varname,'=');
116                 if (varval) {
117                         *varval = 0;
118                         varval++;
119                         ast_cdr_setvar(cdr, varname, varval, 0);
120                 }
121         }
122         
123         if (ast_test_flag(&optflags, OPT_SETANS) && !ast_tvzero(cdr->answer))
124                 newcdr->answer = newcdr->start;
125
126         if (ast_test_flag(&optflags, OPT_SETDISP))
127                 newcdr->disposition = cdr->disposition;
128         
129         if (ast_test_flag(&optflags, OPT_RESETDEST))
130                 newcdr->dstchannel[0] = 0;
131         
132         if (ast_test_flag(&optflags, OPT_ENDCDR))
133                 ast_cdr_end(cdr);
134
135         ast_set_flag(cdr, AST_CDR_FLAG_CHILD | AST_CDR_FLAG_LOCKED);
136 }
137
138 static int forkcdr_exec(struct ast_channel *chan, void *data)
139 {
140         int res = 0;
141         char *argcopy = NULL;
142         struct ast_flags flags = {0};
143         char *opts[OPT_ARG_ARRAY_SIZE];
144         AST_DECLARE_APP_ARGS(arglist,
145                 AST_APP_ARG(options);
146         );
147
148         if (!chan->cdr) {
149                 ast_log(LOG_WARNING, "Channel does not have a CDR\n");
150                 return 0;
151         }
152
153         argcopy = ast_strdupa(data);
154
155         AST_STANDARD_APP_ARGS(arglist, argcopy);
156
157         if (!ast_strlen_zero(arglist.options)) {
158                 ast_app_parse_options(forkcdr_exec_options, &flags, opts, arglist.options);
159         } else
160                 opts[OPT_ARG_VARSET] = 0;
161         
162         if (!ast_strlen_zero(data))
163                 ast_set2_flag(chan->cdr, ast_test_flag(&flags, OPT_KEEPVARS), AST_CDR_FLAG_KEEP_VARS);
164         
165         ast_cdr_fork(chan, flags, opts[OPT_ARG_VARSET]);
166
167         return res;
168 }
169
170 static int unload_module(void)
171 {
172         return ast_unregister_application(app);
173 }
174
175 static int load_module(void)
176 {
177         return ast_register_application(app, forkcdr_exec, synopsis, descrip);
178 }
179
180 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Fork The CDR into 2 separate entities");