Asterisk - The Open Source Telephony Project  21.4.1
func_cdr.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999-2006, Digium, Inc.
5  *
6  * Portions Copyright (C) 2005, Anthony Minessale II
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 related dialplan functions
22  *
23  * \author Anthony Minessale II
24  *
25  * \ingroup functions
26  */
27 
28 /*** MODULEINFO
29  <support_level>core</support_level>
30  ***/
31 
32 #include "asterisk.h"
33 
34 #include "asterisk/module.h"
35 #include "asterisk/channel.h"
36 #include "asterisk/pbx.h"
37 #include "asterisk/utils.h"
38 #include "asterisk/app.h"
39 #include "asterisk/cdr.h"
40 #include "asterisk/stasis.h"
41 #include "asterisk/stasis_message_router.h"
42 
43 /*** DOCUMENTATION
44  <function name="CDR" language="en_US">
45  <synopsis>
46  Gets or sets a CDR variable.
47  </synopsis>
48  <syntax>
49  <parameter name="name" required="true">
50  <para>CDR field name:</para>
51  <enumlist>
52  <enum name="clid">
53  <para>Caller ID.</para>
54  </enum>
55  <enum name="lastdata">
56  <para>Last application arguments.</para>
57  </enum>
58  <enum name="disposition">
59  <para>The final state of the CDR.</para>
60  <enumlist>
61  <enum name="0">
62  <para><literal>NO ANSWER</literal></para>
63  </enum>
64  <enum name="1">
65  <para><literal>NO ANSWER</literal> (NULL record)</para>
66  </enum>
67  <enum name="2">
68  <para><literal>FAILED</literal></para>
69  </enum>
70  <enum name="4">
71  <para><literal>BUSY</literal></para>
72  </enum>
73  <enum name="8">
74  <para><literal>ANSWERED</literal></para>
75  </enum>
76  <enum name="16">
77  <para><literal>CONGESTION</literal></para>
78  </enum>
79  </enumlist>
80  </enum>
81  <enum name="src">
82  <para>Source.</para>
83  </enum>
84  <enum name="start">
85  <para>Time the call started.</para>
86  </enum>
87  <enum name="amaflags">
88  <para>R/W the Automatic Message Accounting (AMA) flags on the channel.
89  When read from a channel, the integer value will always be returned.
90  When written to a channel, both the string format or integer value
91  is accepted.</para>
92  <enumlist>
93  <enum name="1"><para><literal>OMIT</literal></para></enum>
94  <enum name="2"><para><literal>BILLING</literal></para></enum>
95  <enum name="3"><para><literal>DOCUMENTATION</literal></para></enum>
96  </enumlist>
97  <warning><para>Accessing this setting is deprecated in CDR. Please use the CHANNEL function instead.</para></warning>
98  </enum>
99  <enum name="dst">
100  <para>Destination.</para>
101  </enum>
102  <enum name="answer">
103  <para>Time the call was answered.</para>
104  </enum>
105  <enum name="accountcode">
106  <para>The channel's account code.</para>
107  <warning><para>Accessing this setting is deprecated in CDR. Please use the CHANNEL function instead.</para></warning>
108  </enum>
109  <enum name="dcontext">
110  <para>Destination context.</para>
111  </enum>
112  <enum name="end">
113  <para>Time the call ended.</para>
114  </enum>
115  <enum name="uniqueid">
116  <para>The channel's unique id.</para>
117  </enum>
118  <enum name="dstchannel">
119  <para>Destination channel.</para>
120  </enum>
121  <enum name="duration">
122  <para>Duration of the call.</para>
123  </enum>
124  <enum name="userfield">
125  <para>The channel's user specified field.</para>
126  </enum>
127  <enum name="lastapp">
128  <para>Last application.</para>
129  </enum>
130  <enum name="billsec">
131  <para>Duration of the call once it was answered.</para>
132  </enum>
133  <enum name="channel">
134  <para>Channel name.</para>
135  </enum>
136  <enum name="sequence">
137  <para>CDR sequence number.</para>
138  </enum>
139  </enumlist>
140  </parameter>
141  <parameter name="options" required="false">
142  <optionlist>
143  <option name="f">
144  <para>Returns billsec or duration fields as floating point values.</para>
145  </option>
146  <option name="u">
147  <para>Retrieves the raw, unprocessed value.</para>
148  <para>For example, 'start', 'answer', and 'end' will be retrieved as epoch
149  values, when the <literal>u</literal> option is passed, but formatted as YYYY-MM-DD HH:MM:SS
150  otherwise. Similarly, disposition and amaflags will return their raw
151  integral values.</para>
152  </option>
153  </optionlist>
154  </parameter>
155  </syntax>
156  <description>
157  <para>All of the CDR field names are read-only, except for <literal>accountcode</literal>,
158  <literal>userfield</literal>, and <literal>amaflags</literal>. You may, however, supply
159  a name not on the above list, and create your own variable, whose value can be changed
160  with this function, and this variable will be stored on the CDR.</para>
161  <note><para>CDRs can only be modified before the bridge between two channels is
162  torn down. For example, CDRs may not be modified after the <literal>Dial</literal>
163  application has returned.</para></note>
164  <example title="Set the userfield">
165  exten => 1,1,Set(CDR(userfield)=test)
166  </example>
167  </description>
168  </function>
169  <function name="CDR_PROP" language="en_US">
170  <synopsis>
171  Set a property on a channel's CDR.
172  </synopsis>
173  <syntax>
174  <parameter name="name" required="true">
175  <para>The property to set on the CDR.</para>
176  <enumlist>
177  <enum name="party_a">
178  <para>Set this channel as the preferred Party A when
179  channels are associated together.</para>
180  <para>Write-Only</para>
181  </enum>
182  <enum name="disable">
183  <para>Setting to 1 will disable CDRs for this channel.
184  Setting to 0 will enable CDRs for this channel.</para>
185  <para>Write-Only</para>
186  </enum>
187  </enumlist>
188  </parameter>
189  </syntax>
190  <description>
191  <para>This function sets a property on a channel's CDR. Properties
192  alter the behavior of how the CDR operates for that channel.</para>
193  </description>
194  </function>
195  ***/
196 
197 enum cdr_option_flags {
198  OPT_UNPARSED = (1 << 1),
199  OPT_FLOAT = (1 << 2),
200 };
201 
202 AST_APP_OPTIONS(cdr_func_options, {
203  AST_APP_OPTION('f', OPT_FLOAT),
204  AST_APP_OPTION('u', OPT_UNPARSED),
205 });
206 
208  struct ast_channel *chan;
209  const char *cmd;
210  const char *arguments;
211  const char *value;
212  void *data;
213 };
214 
216  char *buf;
217  size_t len;
218 };
219 
220 STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_read_message_type);
221 STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_write_message_type);
222 STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_prop_write_message_type);
223 
224 static struct timeval cdr_retrieve_time(struct ast_channel *chan, const char *time_name)
225 {
226  struct timeval time = { 0 };
227  char *value = NULL;
228  char tempbuf[128];
229  long int tv_sec;
230  long int tv_usec;
231 
232  if (ast_strlen_zero(ast_channel_name(chan))) {
233  /* Format request on a dummy channel */
234  ast_cdr_format_var(ast_channel_cdr(chan), time_name, &value, tempbuf, sizeof(tempbuf), 1);
235  } else {
236  ast_cdr_getvar(ast_channel_name(chan), time_name, tempbuf, sizeof(tempbuf));
237  }
238 
239  /* time.tv_usec is suseconds_t, which could be int or long */
240  if (sscanf(tempbuf, "%ld.%ld", &tv_sec, &tv_usec) == 2) {
241  time.tv_sec = tv_sec;
242  time.tv_usec = tv_usec;
243  } else {
244  ast_log(AST_LOG_WARNING, "Failed to fully extract '%s' from CDR\n", time_name);
245  }
246 
247  return time;
248 }
249 
250 static void cdr_read_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
251 {
252  struct cdr_func_payload *payload = stasis_message_data(message);
253  struct cdr_func_data *output;
254  char *info;
255  char *value = NULL;
256  struct ast_flags flags = { 0 };
257  char tempbuf[512];
259  AST_APP_ARG(variable);
260  AST_APP_ARG(options);
261  );
262 
263  if (cdr_read_message_type() != stasis_message_type(message)) {
264  return;
265  }
266 
267  ast_assert(payload != NULL);
268  output = payload->data;
269  ast_assert(output != NULL);
270 
271  if (ast_strlen_zero(payload->arguments)) {
272  ast_log(AST_LOG_WARNING, "%s requires a variable (%s(variable[,option]))\n)",
273  payload->cmd, payload->cmd);
274  return;
275  }
276  info = ast_strdupa(payload->arguments);
277  AST_STANDARD_APP_ARGS(args, info);
278 
279  if (!ast_strlen_zero(args.options)) {
280  ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
281  }
282 
283  if (ast_strlen_zero(ast_channel_name(payload->chan))) {
284  /* Format request on a dummy channel */
285  ast_cdr_format_var(ast_channel_cdr(payload->chan), args.variable, &value, tempbuf, sizeof(tempbuf), ast_test_flag(&flags, OPT_UNPARSED));
286  if (ast_strlen_zero(value)) {
287  return;
288  }
289  ast_copy_string(tempbuf, value, sizeof(tempbuf));
290  ast_set_flag(&flags, OPT_UNPARSED);
291  } else if (ast_cdr_getvar(ast_channel_name(payload->chan), args.variable, tempbuf, sizeof(tempbuf))) {
292  return;
293  }
294 
295  if (ast_test_flag(&flags, OPT_FLOAT)
296  && (!strcasecmp("billsec", args.variable) || !strcasecmp("duration", args.variable))) {
297  struct timeval start = cdr_retrieve_time(payload->chan, !strcasecmp("billsec", args.variable) ? "answer" : "start");
298  struct timeval finish = cdr_retrieve_time(payload->chan, "end");
299  double delta;
300 
301  if (ast_tvzero(finish)) {
302  finish = ast_tvnow();
303  }
304 
305  if (ast_tvzero(start)) {
306  delta = 0.0;
307  } else {
308  delta = (double)(ast_tvdiff_us(finish, start) / 1000000.0);
309  }
310  snprintf(tempbuf, sizeof(tempbuf), "%lf", delta);
311 
312  } else if (!ast_test_flag(&flags, OPT_UNPARSED)) {
313  if (!strcasecmp("start", args.variable)
314  || !strcasecmp("end", args.variable)
315  || !strcasecmp("answer", args.variable)) {
316  struct timeval fmt_time;
317  struct ast_tm tm;
318  /* tv_usec is suseconds_t, which could be int or long */
319  long int tv_sec;
320  long int tv_usec;
321 
322  if (sscanf(tempbuf, "%ld.%ld", &tv_sec, &tv_usec) != 2) {
323  ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
324  args.variable, tempbuf, ast_channel_name(payload->chan));
325  return;
326  }
327  if (tv_sec) {
328  fmt_time.tv_sec = tv_sec;
329  fmt_time.tv_usec = tv_usec;
330  ast_localtime(&fmt_time, &tm, NULL);
331  ast_strftime(tempbuf, sizeof(tempbuf), "%Y-%m-%d %T", &tm);
332  } else {
333  tempbuf[0] = '\0';
334  }
335  } else if (!strcasecmp("disposition", args.variable)) {
336  int disposition;
337 
338  if (sscanf(tempbuf, "%8d", &disposition) != 1) {
339  ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
340  args.variable, tempbuf, ast_channel_name(payload->chan));
341  return;
342  }
343  snprintf(tempbuf, sizeof(tempbuf), "%s", ast_cdr_disp2str(disposition));
344  } else if (!strcasecmp("amaflags", args.variable)) {
345  int amaflags;
346 
347  if (sscanf(tempbuf, "%8d", &amaflags) != 1) {
348  ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
349  args.variable, tempbuf, ast_channel_name(payload->chan));
350  return;
351  }
352  snprintf(tempbuf, sizeof(tempbuf), "%s", ast_channel_amaflags2string(amaflags));
353  }
354  }
355 
356  ast_copy_string(output->buf, tempbuf, output->len);
357 }
358 
359 static void cdr_write_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
360 {
361  struct cdr_func_payload *payload;
362  struct ast_flags flags = { 0 };
364  AST_APP_ARG(variable);
365  AST_APP_ARG(options);
366  );
367  char *parse;
368 
369  if (cdr_write_message_type() != stasis_message_type(message)) {
370  return;
371  }
372  payload = stasis_message_data(message);
373  if (!payload) {
374  return;
375  }
376  if (ast_strlen_zero(payload->arguments)
377  || !payload->value) {
378  /* Sanity check. cdr_write() could never send these bad messages */
379  ast_assert(0);
380  return;
381  }
382 
383  parse = ast_strdupa(payload->arguments);
384  AST_STANDARD_APP_ARGS(args, parse);
385 
386  if (!ast_strlen_zero(args.options)) {
387  ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
388  }
389 
390  /* These are already handled by cdr_write() */
391  ast_assert(strcasecmp(args.variable, "accountcode")
392  && strcasecmp(args.variable, "peeraccount")
393  && strcasecmp(args.variable, "amaflags"));
394 
395  if (!strcasecmp(args.variable, "userfield")) {
396  ast_cdr_setuserfield(ast_channel_name(payload->chan), payload->value);
397  } else {
398  ast_cdr_setvar(ast_channel_name(payload->chan), args.variable, payload->value);
399  }
400 }
401 
402 static void cdr_prop_write_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
403 {
404  struct cdr_func_payload *payload = stasis_message_data(message);
405  enum ast_cdr_options option;
406  char *parse;
408  AST_APP_ARG(variable);
409  AST_APP_ARG(options);
410  );
411 
412  if (cdr_prop_write_message_type() != stasis_message_type(message)) {
413  return;
414  }
415 
416  if (!payload) {
417  return;
418  }
419 
420  if (ast_strlen_zero(payload->arguments)) {
421  ast_log(AST_LOG_WARNING, "%s requires a variable (%s(variable)=value)\n)",
422  payload->cmd, payload->cmd);
423  return;
424  }
425  if (ast_strlen_zero(payload->value)) {
426  ast_log(AST_LOG_WARNING, "%s requires a value (%s(variable)=value)\n)",
427  payload->cmd, payload->cmd);
428  return;
429  }
430  parse = ast_strdupa(payload->arguments);
431  AST_STANDARD_APP_ARGS(args, parse);
432 
433  if (!strcasecmp("party_a", args.variable)) {
434  option = AST_CDR_FLAG_PARTY_A;
435  } else if (!strcasecmp("disable", args.variable)) {
436  option = AST_CDR_FLAG_DISABLE_ALL;
437  } else {
438  ast_log(AST_LOG_WARNING, "Unknown option %s used with %s\n", args.variable, payload->cmd);
439  return;
440  }
441 
442  if (ast_true(payload->value)) {
443  ast_cdr_set_property(ast_channel_name(payload->chan), option);
444  } else {
445  ast_cdr_clear_property(ast_channel_name(payload->chan), option);
446  }
447 }
448 
449 
450 static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
451  char *buf, size_t len)
452 {
453  RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
454  RAII_VAR(struct cdr_func_payload *, payload, NULL, ao2_cleanup);
455  struct cdr_func_data output = { 0, };
456 
457  if (!chan) {
458  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
459  return -1;
460  }
461 
462  if (!cdr_read_message_type()) {
463  ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: message type not available\n",
464  ast_channel_name(chan));
465  return -1;
466  }
467 
468  payload = ao2_alloc(sizeof(*payload), NULL);
469  if (!payload) {
470  return -1;
471  }
472  payload->chan = chan;
473  payload->cmd = cmd;
474  payload->arguments = parse;
475  payload->data = &output;
476 
477  buf[0] = '\0';/* Ensure the buffer is initialized. */
478  output.buf = buf;
479  output.len = len;
480 
481  message = stasis_message_create(cdr_read_message_type(), payload);
482  if (!message) {
483  ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n",
484  ast_channel_name(chan));
485  return -1;
486  }
487 
488  /* If this is a request on a dummy channel, we're doing post-processing on an
489  * already dispatched CDR. Simply call the callback to calculate the value and
490  * return, instead of posting to Stasis as we would for a running channel.
491  */
492  if (ast_strlen_zero(ast_channel_name(chan))) {
493  cdr_read_callback(NULL, NULL, message);
494  } else {
495  RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
496 
497  if (!router) {
498  ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: no message router\n",
499  ast_channel_name(chan));
500  return -1;
501  }
502  stasis_message_router_publish_sync(router, message);
503  }
504 
505  return 0;
506 }
507 
508 static int cdr_write(struct ast_channel *chan, const char *cmd, char *arguments,
509  const char *value)
510 {
511  struct stasis_message *message;
512  struct cdr_func_payload *payload;
513  struct stasis_message_router *router;
515  AST_APP_ARG(variable);
516  AST_APP_ARG(options);
517  );
518  char *parse;
519 
520  if (!chan) {
521  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
522  return -1;
523  }
524  if (ast_strlen_zero(arguments)) {
525  ast_log(LOG_WARNING, "%s requires a variable (%s(variable)=value)\n)",
526  cmd, cmd);
527  return -1;
528  }
529  if (!value) {
530  ast_log(LOG_WARNING, "%s requires a value (%s(variable)=value)\n)",
531  cmd, cmd);
532  return -1;
533  }
534 
535  parse = ast_strdupa(arguments);
536  AST_STANDARD_APP_ARGS(args, parse);
537 
538  /* These CDR variables are no longer supported or set directly on the channel */
539  if (!strcasecmp(args.variable, "accountcode")) {
540  ast_log(LOG_WARNING, "Using the %s function to set 'accountcode' is deprecated. Please use the CHANNEL function instead.\n",
541  cmd);
542  ast_channel_lock(chan);
543  ast_channel_accountcode_set(chan, value);
544  ast_channel_unlock(chan);
545  return 0;
546  }
547  if (!strcasecmp(args.variable, "amaflags")) {
548  int amaflags;
549 
550  ast_log(LOG_WARNING, "Using the %s function to set 'amaflags' is deprecated. Please use the CHANNEL function instead.\n",
551  cmd);
552  if (isdigit(*value)) {
553  if (sscanf(value, "%30d", &amaflags) != 1) {
554  amaflags = AST_AMA_NONE;
555  }
556  } else {
557  amaflags = ast_channel_string2amaflag(value);
558  }
559  ast_channel_lock(chan);
560  ast_channel_amaflags_set(chan, amaflags);
561  ast_channel_unlock(chan);
562  return 0;
563  }
564  if (!strcasecmp(args.variable, "peeraccount")) {
565  ast_log(LOG_WARNING, "The 'peeraccount' setting is not supported. Please set the 'accountcode' on the appropriate channel using the CHANNEL function.\n");
566  return 0;
567  }
568 
569  /* The remaining CDR variables are handled by CDR processing code */
570  if (!cdr_write_message_type()) {
571  ast_log(LOG_WARNING, "Failed to manipulate CDR for channel %s: message type not available\n",
572  ast_channel_name(chan));
573  return -1;
574  }
575 
576  payload = ao2_alloc(sizeof(*payload), NULL);
577  if (!payload) {
578  return -1;
579  }
580  payload->chan = chan;
581  payload->cmd = cmd;
582  payload->arguments = arguments;
583  payload->value = value;
584 
585  message = stasis_message_create(cdr_write_message_type(), payload);
586  ao2_ref(payload, -1);
587  if (!message) {
588  ast_log(LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n",
589  ast_channel_name(chan));
590  return -1;
591  }
592  router = ast_cdr_message_router();
593  if (!router) {
594  ast_log(LOG_WARNING, "Failed to manipulate CDR for channel %s: no message router\n",
595  ast_channel_name(chan));
596  ao2_ref(message, -1);
597  return -1;
598  }
599  stasis_message_router_publish_sync(router, message);
600  ao2_ref(router, -1);
601  ao2_ref(message, -1);
602 
603  return 0;
604 }
605 
606 static int cdr_prop_write(struct ast_channel *chan, const char *cmd, char *parse,
607  const char *value)
608 {
609  RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
610  RAII_VAR(struct cdr_func_payload *, payload, NULL, ao2_cleanup);
611  RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
612 
613  if (!chan) {
614  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
615  return -1;
616  }
617 
618  if (!router) {
619  ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: no message router\n",
620  ast_channel_name(chan));
621  return -1;
622  }
623 
624  if (!cdr_prop_write_message_type()) {
625  ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: message type not available\n",
626  ast_channel_name(chan));
627  return -1;
628  }
629 
630  payload = ao2_alloc(sizeof(*payload), NULL);
631  if (!payload) {
632  return -1;
633  }
634  payload->chan = chan;
635  payload->cmd = cmd;
636  payload->arguments = parse;
637  payload->value = value;
638 
639  message = stasis_message_create(cdr_prop_write_message_type(), payload);
640  if (!message) {
641  ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n",
642  ast_channel_name(chan));
643  return -1;
644  }
645  stasis_message_router_publish_sync(router, message);
646 
647  return 0;
648 }
649 
650 static struct ast_custom_function cdr_function = {
651  .name = "CDR",
652  .read = cdr_read,
653  .write = cdr_write,
654 };
655 
656 static struct ast_custom_function cdr_prop_function = {
657  .name = "CDR_PROP",
658  .read = NULL,
659  .write = cdr_prop_write,
660 };
661 
662 static int unload_module(void)
663 {
664  RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
665  int res = 0;
666 
667  if (router) {
668  stasis_message_router_remove(router, cdr_prop_write_message_type());
669  stasis_message_router_remove(router, cdr_write_message_type());
670  stasis_message_router_remove(router, cdr_read_message_type());
671  }
672  STASIS_MESSAGE_TYPE_CLEANUP(cdr_read_message_type);
673  STASIS_MESSAGE_TYPE_CLEANUP(cdr_write_message_type);
674  STASIS_MESSAGE_TYPE_CLEANUP(cdr_prop_write_message_type);
675  res |= ast_custom_function_unregister(&cdr_function);
676  res |= ast_custom_function_unregister(&cdr_prop_function);
677 
678  return res;
679 }
680 
681 static int load_module(void)
682 {
683  RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
684  int res = 0;
685 
686  if (!router) {
688  }
689 
690  res |= STASIS_MESSAGE_TYPE_INIT(cdr_read_message_type);
691  res |= STASIS_MESSAGE_TYPE_INIT(cdr_write_message_type);
692  res |= STASIS_MESSAGE_TYPE_INIT(cdr_prop_write_message_type);
693  res |= ast_custom_function_register(&cdr_function);
694  res |= ast_custom_function_register(&cdr_prop_function);
695  res |= stasis_message_router_add(router, cdr_prop_write_message_type(),
696  cdr_prop_write_callback, NULL);
697  res |= stasis_message_router_add(router, cdr_write_message_type(),
698  cdr_write_callback, NULL);
699  res |= stasis_message_router_add(router, cdr_read_message_type(),
700  cdr_read_callback, NULL);
701 
702  if (res) {
703  unload_module();
705  }
707 }
708 
709 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Call Detail Record (CDR) dialplan functions",
710  .support_level = AST_MODULE_SUPPORT_CORE,
711  .load = load_module,
712  .unload = unload_module,
713  .requires = "cdr",
714 );
const char * name
Definition: pbx.h:119
Main Channel structure associated with a channel.
int ast_cdr_setvar(const char *channel_name, const char *name, const char *value)
Set a variable on a CDR.
Definition: cdr.c:3240
Asterisk main include file. File version handling, generic pbx functions.
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.
int ast_cdr_getvar(const char *channel_name, const char *name, char *value, size_t length)
Retrieve a CDR variable from a channel's current CDR.
Definition: cdr.c:3386
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
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
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:117
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
Definition: channel.c:4373
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
const char * data
ast_cdr_options
CDR manipulation options. Certain function calls will manipulate the state of a CDR object based on t...
Definition: cdr.h:242
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
Utility functions.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
enum ama_flags ast_channel_string2amaflag(const char *flag)
Convert a string to a detail record AMA flag.
Definition: channel.c:4360
Call Detail Record API.
void ast_cdr_format_var(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int raw)
Format a CDR variable from an already posted CDR.
Definition: cdr.c:3112
struct stasis_message_router * ast_cdr_message_router(void)
Return the message router for the CDR engine.
Definition: cdr.c:4356
General Asterisk PBX channel definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ast_channel_amaflags_set(struct ast_channel *chan, enum ama_flags value)
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3066
Core PBX routines and definitions.
int ast_cdr_set_property(const char *channel_name, enum ast_cdr_options option)
Set a property on a CDR for a channel.
Definition: cdr.c:3610
const char * ast_cdr_disp2str(int disposition)
Disposition to a string.
Definition: cdr.c:3492
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: utils.c:2199
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_message_router_remove(struct stasis_message_router *router, struct stasis_message_type *message_type)
Remove a route from a message router.
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
void ast_cdr_setuserfield(const char *channel_name, const char *userfield)
Set CDR user field for channel (stored in CDR)
Definition: cdr.c:3539
Structure used to handle boolean flags.
Definition: utils.h:199
STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_sync_message_type)
A message type used to synchronize with the CDR topic.
void stasis_message_router_publish_sync(struct stasis_message_router *router, struct stasis_message *message)
Publish a message to a message router's subscription synchronously.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
int ast_cdr_clear_property(const char *channel_name, enum ast_cdr_options option)
Clear a property on a CDR for a channel.
Definition: cdr.c:3637
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition: time.h:87
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
#define AST_APP_ARG(name)
Define an application argument.