Asterisk - The Open Source Telephony Project  18.5.0
cdr_manager.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2004 - 2005
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16 
17 /*!
18  * \file
19  * \brief Asterisk Call Manager CDR records.
20  *
21  * See also
22  * \arg \ref AstCDR
23  * \arg \ref AstAMI
24  * \arg \ref Config_ami
25  * \ingroup cdr_drivers
26  */
27 
28 /*! \li \ref cdr_manager.c uses the configuration file \ref cdr_manager.conf
29  * \addtogroup configuration_file Configuration Files
30  */
31 
32 /*!
33  * \page cdr_manager.conf cdr_manager.conf
34  * \verbinclude cdr_manager.conf.sample
35  */
36 
37 /*** MODULEINFO
38  <support_level>core</support_level>
39  ***/
40 
41 /*** DOCUMENTATION
42  <managerEvent language="en_US" name="Cdr">
43  <managerEventInstance class="EVENT_FLAG_CDR">
44  <synopsis>Raised when a CDR is generated.</synopsis>
45  <syntax>
46  <parameter name="AccountCode">
47  <para>The account code of the Party A channel.</para>
48  </parameter>
49  <parameter name="Source">
50  <para>The Caller ID number associated with the Party A in the CDR.</para>
51  </parameter>
52  <parameter name="Destination">
53  <para>The dialplan extension the Party A was executing.</para>
54  </parameter>
55  <parameter name="DestinationContext">
56  <para>The dialplan context the Party A was executing.</para>
57  </parameter>
58  <parameter name="CallerID">
59  <para>The Caller ID name associated with the Party A in the CDR.</para>
60  </parameter>
61  <parameter name="Channel">
62  <para>The channel name of the Party A.</para>
63  </parameter>
64  <parameter name="DestinationChannel">
65  <para>The channel name of the Party B.</para>
66  </parameter>
67  <parameter name="LastApplication">
68  <para>The last dialplan application the Party A executed.</para>
69  </parameter>
70  <parameter name="LastData">
71  <para>
72  The parameters passed to the last dialplan application the
73  Party A executed.
74  </para>
75  </parameter>
76  <parameter name="StartTime">
77  <para>The time the CDR was created.</para>
78  </parameter>
79  <parameter name="AnswerTime">
80  <para>
81  The earliest of either the time when Party A answered, or
82  the start time of this CDR.
83  </para>
84  </parameter>
85  <parameter name="EndTime">
86  <para>
87  The time when the CDR was finished. This occurs when the
88  Party A hangs up or when the bridge between Party A and
89  Party B is broken.
90  </para>
91  </parameter>
92  <parameter name="Duration">
93  <para>The time, in seconds, of <replaceable>EndTime</replaceable> - <replaceable>StartTime</replaceable>.</para>
94  </parameter>
95  <parameter name="BillableSeconds">
96  <para>The time, in seconds, of <replaceable>AnswerTime</replaceable> - <replaceable>StartTime</replaceable>.</para>
97  </parameter>
98  <parameter name="Disposition">
99  <para>The final known disposition of the CDR.</para>
100  <enumlist>
101  <enum name="NO ANSWER">
102  <para>The channel was not answered. This is the default disposition.</para>
103  </enum>
104  <enum name="FAILED">
105  <para>The channel attempted to dial but the call failed.</para>
106  <note>
107  <para>The congestion setting in <filename>cdr.conf</filename> can result
108  in the <literal>AST_CAUSE_CONGESTION</literal> hang up cause or the
109  <literal>CONGESTION</literal> dial status to map to this disposition.
110  </para>
111  </note>
112  </enum>
113  <enum name="BUSY">
114  <para>The channel attempted to dial but the remote party was busy.</para>
115  </enum>
116  <enum name="ANSWERED">
117  <para>The channel was answered. The hang up cause will no longer
118  impact the disposition of the CDR.</para>
119  </enum>
120  <enum name="CONGESTION">
121  <para>The channel attempted to dial but the remote party was congested.</para>
122  </enum>
123  </enumlist>
124  </parameter>
125  <parameter name="AMAFlags">
126  <para>A flag that informs a billing system how to treat the CDR.</para>
127  <enumlist>
128  <enum name="OMIT">
129  <para>This CDR should be ignored.</para>
130  </enum>
131  <enum name="BILLING">
132  <para>This CDR contains valid billing data.</para>
133  </enum>
134  <enum name="DOCUMENTATION">
135  <para>This CDR is for documentation purposes.</para>
136  </enum>
137  </enumlist>
138  </parameter>
139  <parameter name="UniqueID">
140  <para>A unique identifier for the Party A channel.</para>
141  </parameter>
142  <parameter name="UserField">
143  <para>
144  A user defined field set on the channels. If set on both the Party A
145  and Party B channel, the userfields of both are concatenated and
146  separated by a <literal>;</literal>.
147  </para>
148  </parameter>
149  </syntax>
150  <description>
151  <para>
152  The <replaceable>Cdr</replaceable> event is only raised when the
153  <filename>cdr_manager</filename> backend is loaded and registered with
154  the CDR engine.
155  </para>
156  <note>
157  <para>
158  This event can contain additional fields depending on the configuration
159  provided by <filename>cdr_manager.conf</filename>.
160  </para>
161  </note>
162  </description>
163  </managerEventInstance>
164  </managerEvent>
165  ***/
166 
167 #include "asterisk.h"
168 
169 #include <time.h>
170 
171 #include "asterisk/channel.h"
172 #include "asterisk/cdr.h"
173 #include "asterisk/module.h"
174 #include "asterisk/utils.h"
175 #include "asterisk/manager.h"
176 #include "asterisk/config.h"
177 #include "asterisk/pbx.h"
178 
179 #define DATE_FORMAT "%Y-%m-%d %T"
180 #define CONF_FILE "cdr_manager.conf"
181 #define CUSTOM_FIELDS_BUF_SIZE 1024
182 
183 static const char name[] = "cdr_manager";
184 
185 static int enablecdr = 0;
186 
187 static struct ast_str *customfields;
189 
190 static int manager_log(struct ast_cdr *cdr);
191 
192 static int load_config(int reload)
193 {
194  char *cat = NULL;
195  struct ast_config *cfg;
196  struct ast_variable *v;
197  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
198  int newenablecdr = 0;
199 
200  cfg = ast_config_load(CONF_FILE, config_flags);
201  if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
202  return 0;
203  }
204 
205  if (cfg == CONFIG_STATUS_FILEINVALID) {
206  ast_log(LOG_ERROR, "Config file '%s' could not be parsed\n", CONF_FILE);
207  return -1;
208  }
209 
210  if (!cfg) {
211  /* Standard configuration */
212  ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n");
213  if (enablecdr) {
215  }
216  enablecdr = 0;
217  return -1;
218  }
219 
220  if (reload) {
222  }
223 
224  if (reload && customfields) {
225  ast_free(customfields);
226  customfields = NULL;
227  }
228 
229  while ( (cat = ast_category_browse(cfg, cat)) ) {
230  if (!strcasecmp(cat, "general")) {
231  v = ast_variable_browse(cfg, cat);
232  while (v) {
233  if (!strcasecmp(v->name, "enabled"))
234  newenablecdr = ast_true(v->value);
235 
236  v = v->next;
237  }
238  } else if (!strcasecmp(cat, "mappings")) {
239  customfields = ast_str_create(CUSTOM_FIELDS_BUF_SIZE);
240  v = ast_variable_browse(cfg, cat);
241  while (v) {
242  if (customfields && !ast_strlen_zero(v->name) && !ast_strlen_zero(v->value)) {
243  if ((ast_str_strlen(customfields) + strlen(v->value) + strlen(v->name) + 14) < ast_str_size(customfields)) {
244  ast_str_append(&customfields, -1, "%s: ${CDR(%s)}\r\n", v->value, v->name);
245  ast_log(LOG_NOTICE, "Added mapping %s: ${CDR(%s)}\n", v->value, v->name);
246  } else {
247  ast_log(LOG_WARNING, "No more buffer space to add other custom fields\n");
248  break;
249  }
250 
251  }
252  v = v->next;
253  }
254  }
255  }
256 
257  if (reload) {
259  }
260 
261  ast_config_destroy(cfg);
262 
263  if (!newenablecdr) {
265  } else if (newenablecdr) {
267  }
268  enablecdr = newenablecdr;
269 
270  return 0;
271 }
272 
273 static int manager_log(struct ast_cdr *cdr)
274 {
275  struct ast_tm timeresult;
276  char strStartTime[80] = "";
277  char strAnswerTime[80] = "";
278  char strEndTime[80] = "";
280 
281  if (!enablecdr)
282  return 0;
283 
284  ast_localtime(&cdr->start, &timeresult, NULL);
285  ast_strftime(strStartTime, sizeof(strStartTime), DATE_FORMAT, &timeresult);
286 
287  if (cdr->answer.tv_sec) {
288  ast_localtime(&cdr->answer, &timeresult, NULL);
289  ast_strftime(strAnswerTime, sizeof(strAnswerTime), DATE_FORMAT, &timeresult);
290  }
291 
292  ast_localtime(&cdr->end, &timeresult, NULL);
293  ast_strftime(strEndTime, sizeof(strEndTime), DATE_FORMAT, &timeresult);
294 
295  buf[0] = '\0';
297  if (customfields && ast_str_strlen(customfields)) {
299  if (!dummy) {
300  ast_log(LOG_ERROR, "Unable to allocate channel for variable substitution.\n");
301  return 0;
302  }
303  ast_channel_cdr_set(dummy, ast_cdr_dup(cdr));
304  pbx_substitute_variables_helper(dummy, ast_str_buffer(customfields), buf, sizeof(buf) - 1);
305  ast_channel_unref(dummy);
306  }
308 
310  "AccountCode: %s\r\n"
311  "Source: %s\r\n"
312  "Destination: %s\r\n"
313  "DestinationContext: %s\r\n"
314  "CallerID: %s\r\n"
315  "Channel: %s\r\n"
316  "DestinationChannel: %s\r\n"
317  "LastApplication: %s\r\n"
318  "LastData: %s\r\n"
319  "StartTime: %s\r\n"
320  "AnswerTime: %s\r\n"
321  "EndTime: %s\r\n"
322  "Duration: %ld\r\n"
323  "BillableSeconds: %ld\r\n"
324  "Disposition: %s\r\n"
325  "AMAFlags: %s\r\n"
326  "UniqueID: %s\r\n"
327  "UserField: %s\r\n"
328  "%s",
329  cdr->accountcode, cdr->src, cdr->dst, cdr->dcontext, cdr->clid, cdr->channel,
330  cdr->dstchannel, cdr->lastapp, cdr->lastdata, strStartTime, strAnswerTime, strEndTime,
331  cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition),
333 
334  return 0;
335 }
336 
337 static int unload_module(void)
338 {
339  if (ast_cdr_unregister(name)) {
340  return -1;
341  }
342 
343  if (customfields)
344  ast_free(customfields);
345 
346  return 0;
347 }
348 
349 static int load_module(void)
350 {
351  if (ast_cdr_register(name, "Asterisk Manager Interface CDR Backend", manager_log)) {
353  }
354 
355  if (load_config(0)) {
358  }
359 
361 }
362 
363 static int reload(void)
364 {
365  return load_config(1);
366 }
367 
368 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk Manager Interface CDR Backend",
369  .support_level = AST_MODULE_SUPPORT_CORE,
370  .load = load_module,
371  .unload = unload_module,
372  .reload = reload,
373  .load_pri = AST_MODPRI_CDR_DRIVER,
374  .requires = "cdr",
375 );
struct ast_variable * next
#define ast_rwlock_rdlock(a)
Definition: lock.h:233
#define EVENT_FLAG_CDR
Definition: manager.h:81
int ast_cdr_backend_suspend(const char *name)
Suspend a CDR backend temporarily.
Definition: cdr.c:2866
Main Channel structure associated with a channel.
char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: cdr.h:308
Asterisk main include file. File version handling, generic pbx functions.
int ast_cdr_unregister(const char *name)
Unregister a CDR handling engine.
Definition: cdr.c:2988
#define AST_RWLOCK_DEFINE_STATIC(rwlock)
Definition: lock.h:541
static int enablecdr
Definition: cdr_manager.c:185
char dstchannel[AST_MAX_EXTENSION]
Definition: cdr.h:288
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
static struct ast_str * customfields
Definition: cdr_manager.c:187
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition: strings.h:699
Time-related functions and macros.
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
long int billsec
Definition: cdr.h:302
#define LOG_WARNING
Definition: logger.h:274
static int reload(void)
Definition: cdr_manager.c:363
#define CUSTOM_FIELDS_BUF_SIZE
Definition: cdr_manager.c:181
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
int ast_cdr_backend_unsuspend(const char *name)
Unsuspend a CDR backend.
Definition: cdr.c:2884
static void dummy(char *unused,...)
Definition: chan_unistim.c:220
#define CONFIG_STATUS_FILEINVALID
char dcontext[AST_MAX_EXTENSION]
Definition: cdr.h:284
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
Structure for variables, used for configurations and for channel variables.
static int unload_module(void)
Definition: cdr_manager.c:337
struct ast_cdr * ast_cdr_dup(struct ast_cdr *cdr)
Duplicate a public CDR.
Definition: cdr.c:2998
static int load_config(int reload)
Definition: cdr_manager.c:192
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
Definition: channel.c:4418
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
static int load_module(void)
Definition: cdr_manager.c:349
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
#define NULL
Definition: resample.c:96
#define ast_rwlock_unlock(a)
Definition: lock.h:232
Utility functions.
#define ast_strlen_zero(foo)
Definition: strings.h:52
Call Detail Record API.
char lastdata[AST_MAX_EXTENSION]
Definition: cdr.h:292
Configuration File Parser.
long int amaflags
Definition: cdr.h:306
#define ast_log
Definition: astobj2.c:42
void ast_channel_cdr_set(struct ast_channel *chan, struct ast_cdr *value)
#define ast_config_load(filename, flags)
Load a config file.
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
Register a CDR handling engine.
Definition: cdr.c:2943
General Asterisk PBX channel definitions.
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1283
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
char uniqueid[AST_MAX_UNIQUEID]
Definition: cdr.h:314
char dst[AST_MAX_EXTENSION]
Definition: cdr.h:282
char channel[AST_MAX_EXTENSION]
Definition: cdr.h:286
#define CONF_FILE
Definition: cdr_manager.c:180
Core PBX routines and definitions.
#define CONFIG_STATUS_FILEUNCHANGED
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
struct timeval answer
Definition: cdr.h:296
Responsible for call detail data.
Definition: cdr.h:276
char lastapp[AST_MAX_EXTENSION]
Definition: cdr.h:290
const char * ast_cdr_disp2str(int disposition)
Disposition to a string.
Definition: cdr.c:3430
#define LOG_ERROR
Definition: logger.h:285
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
static const char name[]
Definition: cdr_manager.c:183
static int manager_log(struct ast_cdr *cdr)
Definition: cdr_manager.c:273
#define LOG_NOTICE
Definition: logger.h:263
struct timeval start
Definition: cdr.h:294
#define ast_free(a)
Definition: astmm.h:182
long int duration
Definition: cdr.h:300
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
Structure used to handle boolean flags.
Definition: utils.h:199
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
char src[AST_MAX_EXTENSION]
Definition: cdr.h:280
#define ast_rwlock_wrlock(a)
Definition: lock.h:234
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
struct timeval end
Definition: cdr.h:298
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211
long int disposition
Definition: cdr.h:304
char clid[AST_MAX_EXTENSION]
Definition: cdr.h:278
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:248
Asterisk module definitions.
static ast_rwlock_t customfields_lock
Definition: cdr_manager.c:188
#define DATE_FORMAT
Definition: cdr_manager.c:179
char userfield[AST_MAX_USER_FIELD]
Definition: cdr.h:318
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620