Asterisk - The Open Source Telephony Project  GIT-master-b91fb3c
aoc.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2010, Digium, Inc.
5  *
6  * David Vossel <dvossel@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 /*!
20  * \file
21  * \brief generic AOC payload generation encoding and decoding
22  *
23  * \author David Vossel <dvossel@digium.com>
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 #include "asterisk/aoc.h"
33 #include "asterisk/utils.h"
34 #include "asterisk/strings.h"
35 #include "asterisk/_private.h"
36 #include "asterisk/cli.h"
37 #include "asterisk/manager.h"
40 
41 /*** DOCUMENTATION
42  <managerEvent language="en_US" name="AOC-S">
43  <managerEventInstance class="EVENT_FLAG_AOC">
44  <synopsis>Raised when an Advice of Charge message is sent at the beginning of a call.</synopsis>
45  <syntax>
46  <channel_snapshot/>
47  <parameter name="Chargeable" />
48  <parameter name="RateType">
49  <enumlist>
50  <enum name="NotAvailable" />
51  <enum name="Free" />
52  <enum name="FreeFromBeginning" />
53  <enum name="Duration" />
54  <enum name="Flag" />
55  <enum name="Volume" />
56  <enum name="SpecialCode" />
57  </enumlist>
58  </parameter>
59  <parameter name="Currency" />
60  <parameter name="Name" />
61  <parameter name="Cost" />
62  <parameter name="Multiplier">
63  <enumlist>
64  <enum name="1/1000" />
65  <enum name="1/100" />
66  <enum name="1/10" />
67  <enum name="1" />
68  <enum name="10" />
69  <enum name="100" />
70  <enum name="1000" />
71  </enumlist>
72  </parameter>
73  <parameter name="ChargingType" />
74  <parameter name="StepFunction" />
75  <parameter name="Granularity" />
76  <parameter name="Length" />
77  <parameter name="Scale" />
78  <parameter name="Unit">
79  <enumlist>
80  <enum name="Octect" />
81  <enum name="Segment" />
82  <enum name="Message" />
83  </enumlist>
84  </parameter>
85  <parameter name="SpecialCode" />
86  </syntax>
87  <see-also>
88  <ref type="managerEvent">AOC-D</ref>
89  <ref type="managerEvent">AOC-E</ref>
90  </see-also>
91  </managerEventInstance>
92  </managerEvent>
93  <managerEvent language="en_US" name="AOC-D">
94  <managerEventInstance class="EVENT_FLAG_AOC">
95  <synopsis>Raised when an Advice of Charge message is sent during a call.</synopsis>
96  <syntax>
97  <channel_snapshot/>
98  <parameter name="Charge" />
99  <parameter name="Type">
100  <enumlist>
101  <enum name="NotAvailable" />
102  <enum name="Free" />
103  <enum name="Currency" />
104  <enum name="Units" />
105  </enumlist>
106  </parameter>
107  <parameter name="BillingID">
108  <enumlist>
109  <enum name="Normal" />
110  <enum name="Reverse" />
111  <enum name="CreditCard" />
112  <enum name="CallForwardingUnconditional" />
113  <enum name="CallForwardingBusy" />
114  <enum name="CallForwardingNoReply" />
115  <enum name="CallDeflection" />
116  <enum name="CallTransfer" />
117  <enum name="NotAvailable" />
118  </enumlist>
119  </parameter>
120  <parameter name="TotalType">
121  <enumlist>
122  <enum name="SubTotal" />
123  <enum name="Total" />
124  </enumlist>
125  </parameter>
126  <parameter name="Currency" />
127  <parameter name="Name" />
128  <parameter name="Cost" />
129  <parameter name="Multiplier">
130  <enumlist>
131  <enum name="1/1000" />
132  <enum name="1/100" />
133  <enum name="1/10" />
134  <enum name="1" />
135  <enum name="10" />
136  <enum name="100" />
137  <enum name="1000" />
138  </enumlist>
139  </parameter>
140  <parameter name="Units" />
141  <parameter name="NumberOf" />
142  <parameter name="TypeOf" />
143  </syntax>
144  <see-also>
145  <ref type="manager">AOCMessage</ref>
146  <ref type="managerEvent">AOC-S</ref>
147  <ref type="managerEvent">AOC-E</ref>
148  </see-also>
149  </managerEventInstance>
150  </managerEvent>
151  <managerEvent language="en_US" name="AOC-E">
152  <managerEventInstance class="EVENT_FLAG_AOC">
153  <synopsis>Raised when an Advice of Charge message is sent at the end of a call.</synopsis>
154  <syntax>
155  <channel_snapshot/>
156  <parameter name="ChargingAssociation" />
157  <parameter name="Number" />
158  <parameter name="Plan" />
159  <parameter name="ID" />
160  <xi:include xpointer="xpointer(/docs/managerEvent[@name='AOC-D']/managerEventInstance/syntax/parameter)" />
161  </syntax>
162  <see-also>
163  <ref type="manager">AOCMessage</ref>
164  <ref type="managerEvent">AOC-S</ref>
165  <ref type="managerEvent">AOC-D</ref>
166  </see-also>
167  </managerEventInstance>
168  </managerEvent>
169 ***/
170 
171 /* Encoded Payload Flags */
172 #define AST_AOC_ENCODED_TYPE_REQUEST (0 << 0)
173 #define AST_AOC_ENCODED_TYPE_D (1 << 0)
174 #define AST_AOC_ENCODED_TYPE_E (2 << 0)
175 #define AST_AOC_ENCODED_TYPE_S (3 << 0)
176 
177 #define AST_AOC_ENCODED_REQUEST_S (1 << 2)
178 #define AST_AOC_ENCODED_REQUEST_D (1 << 3)
179 #define AST_AOC_ENCODED_REQUEST_E (1 << 4)
180 
181 #define AST_AOC_ENCODED_CHARGE_NA (0 << 5)
182 #define AST_AOC_ENCODED_CHARGE_FREE (1 << 5)
183 #define AST_AOC_ENCODED_CHARGE_CURRENCY (2 << 5)
184 #define AST_AOC_ENCODED_CHARGE_UNIT (3 << 5)
185 
186 #define AST_AOC_ENCODED_CHARGE_SUBTOTAL (1 << 7)
187 #define AST_AOC_ENCODED_CHARGE_TOTAL (0 << 7)
188 
189 #define AST_AOC_ENCODE_VERSION 1
190 
191 
192 static char aoc_debug_enabled = 0;
193 static void aoc_display_decoded_debug(const struct ast_aoc_decoded *decoded, int decoding, struct ast_channel *chan);
194 static int aoc_s_add_entry(struct ast_aoc_decoded *decoded, struct ast_aoc_s_entry *entry);
195 
196 /* AOC Payload Header. Holds all the encoded AOC data to pass on the wire */
198  uint8_t version;
199  uint8_t flags;
200  uint16_t datalen;
201  unsigned char data[0];
202 };
203 
204 /* Decoded AOC data */
206  enum ast_aoc_type msg_type;
207  enum ast_aoc_charge_type charge_type;
208  enum ast_aoc_request request_flag;
209  enum ast_aoc_total_type total_type;
210 
211  /* currency information */
213  unsigned int currency_amount;
214  char currency_name[AOC_CURRENCY_NAME_SIZE];
215 
216  /* unit information */
218  struct ast_aoc_unit_entry unit_list[32];
219 
220  /* Billing Id */
221  enum ast_aoc_billing_id billing_id;
222 
223  /* Charging Association information */
224  struct ast_aoc_charging_association charging_association;
225 
226  /* AOC-S charge information */
228  struct ast_aoc_s_entry aoc_s_entries[10];
229 
230  /* Is this an AOC Termination Request */
232 };
233 
234 /*! \brief AOC Payload Information Elements */
235 enum AOC_IE {
242 };
243 
244 /*! \brief AOC IE payload header */
246  uint8_t ie_id;
247  uint8_t datalen;
248  char data[0];
249 } __attribute__((packed));
250 
252  uint32_t amount;
253  uint8_t multiplier;
255 } __attribute__((packed));
256 
257 struct aoc_ie_unit {
258  uint32_t amount;
259  uint8_t valid_type;
260  uint8_t valid_amount;
261  uint8_t type;
262 } __attribute__((packed));
263 
265  uint8_t id;
266 } __attribute__((packed));
267 
270 } __attribute__((packed));
271 
274 } __attribute__((packed));
275 
277  const enum ast_aoc_charge_type charge_type,
278  const enum ast_aoc_request requests)
279 {
280  struct ast_aoc_decoded *decoded = NULL;
281 
282  /* verify input */
283  if (((unsigned int) charge_type > AST_AOC_CHARGE_UNIT) ||
284  ((unsigned int) msg_type > AST_AOC_E) ||
285  ((msg_type == AST_AOC_REQUEST) && !requests)) {
286 
287  ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object, invalid input\n");
288  return NULL;
289  }
290 
291  if (!(decoded = ast_calloc(1, sizeof(struct ast_aoc_decoded)))) {
292  ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object \n");
293  return NULL;
294  }
295 
296  decoded->msg_type = msg_type;
297 
298  if (msg_type == AST_AOC_REQUEST) {
299  decoded->request_flag = requests;
300  } else if ((msg_type == AST_AOC_D) || (msg_type == AST_AOC_E)) {
301  decoded->charge_type = charge_type;
302  }
303 
304  return decoded;
305 }
306 
308 {
309  ast_free(decoded);
310  return NULL;
311 }
312 
314 {
315  ast_free(encoded);
316  return NULL;
317 }
318 
319 static void aoc_parse_ie_charging_rate(struct ast_aoc_decoded *decoded, const struct aoc_ie_charging_rate *ie)
320 {
321  struct ast_aoc_s_entry entry = { 0, };
322 
323  entry.charged_item = ntohs(ie->entry.charged_item);
324  entry.rate_type = ntohs(ie->entry.rate_type);
325 
326  switch (entry.rate_type) {
328  entry.rate.duration.multiplier = ntohs(ie->entry.rate.duration.multiplier);
329  entry.rate.duration.amount = ntohl(ie->entry.rate.duration.amount);
330  entry.rate.duration.time = ntohl(ie->entry.rate.duration.time);
331  entry.rate.duration.time_scale = ntohs(ie->entry.rate.duration.time_scale);
334  entry.rate.duration.charging_type = ie->entry.rate.duration.charging_type; /* only one byte */
335 
339  sizeof(entry.rate.duration.currency_name));
340  }
341  break;
343  entry.rate.flat.multiplier = ntohs(ie->entry.rate.flat.multiplier);
344  entry.rate.flat.amount = ntohl(ie->entry.rate.flat.amount);
348  sizeof(entry.rate.flat.currency_name));
349  }
350  break;
352  entry.rate.volume.multiplier = ntohs(ie->entry.rate.volume.multiplier);
353  entry.rate.volume.amount = ntohl(ie->entry.rate.volume.amount);
354  entry.rate.volume.volume_unit = ntohs(ie->entry.rate.volume.volume_unit);
358  sizeof(entry.rate.volume.currency_name));
359  }
360  break;
362  entry.rate.special_code = ntohs(ie->entry.rate.special_code);
363  break;
364  }
365 
366  aoc_s_add_entry(decoded, &entry);
367 }
368 
369 static int aoc_parse_ie(struct ast_aoc_decoded *decoded, unsigned char *data, unsigned int datalen)
370 {
371  enum AOC_IE ie_id;
372  unsigned int len;
373 
374  while (datalen >= 2) {
375  ie_id = data[0];
376  len = data[1];
377  if (len > datalen -2) {
378  ast_log(LOG_ERROR, "AOC information element length exceeds the total message size\n");
379  return -1;
380  }
381 
382  switch(ie_id) {
383  case AOC_IE_CURRENCY:
384  if (len == sizeof(struct aoc_ie_currency)) {
385  struct aoc_ie_currency ie;
386  memcpy(&ie, data + 2, len);
387  decoded->currency_amount = ntohl(ie.amount);
388  decoded->multiplier = ie.multiplier; /* only one byte */
389  memcpy(decoded->currency_name, ie.name, sizeof(decoded->currency_name));
390  } else {
391  ast_log(LOG_WARNING, "Received invalid currency ie\n");
392  }
393  break;
394  case AOC_IE_UNIT:
395  if (len == sizeof(struct aoc_ie_unit)) {
396  struct aoc_ie_unit ie;
397  memcpy(&ie, data + 2, len);
398  ast_aoc_add_unit_entry(decoded, ie.valid_amount, ntohl(ie.amount), ie.valid_type, ie.type);
399  } else {
400  ast_log(LOG_WARNING, "Received invalid unit ie\n");
401  }
402  break;
403  case AOC_IE_BILLING:
404  if (len == sizeof(struct aoc_ie_billing)) {
405  struct aoc_ie_billing ie;
406  memcpy(&ie, data + 2, len);
407  decoded->billing_id = ie.id; /* only one byte */
408  } else {
409  ast_log(LOG_WARNING, "Received invalid billing ie\n");
410  }
411  break;
413  if (len == sizeof(struct aoc_ie_charging_association)) {
414  memcpy(&decoded->charging_association, data + 2, sizeof(decoded->charging_association));
415  /* everything in the charging_association struct is a single byte except for the id */
417  decoded->charging_association.charge.id = ntohl(decoded->charging_association.charge.id);
418  }
419  } else {
420  ast_log(LOG_WARNING, "Received invalid charging association ie\n");
421  }
422  break;
423  case AOC_IE_RATE:
424  if (len == sizeof(struct aoc_ie_charging_rate)) {
425  struct aoc_ie_charging_rate ie;
426  memcpy(&ie, data + 2, len);
427  aoc_parse_ie_charging_rate(decoded, &ie);
428  } else {
429  ast_log(LOG_WARNING, "Received invalid charging rate ie\n");
430  }
431  break;
433  if (len == 0) {
434  decoded->termination_request = 1;
435  } else {
436  ast_log(LOG_WARNING, "Received invalid termination request ie\n");
437  }
438  break;
439  default:
440  ast_log(LOG_WARNING, "Unknown AOC Information Element, ignoring.\n");
441  }
442 
443  datalen -= (len + 2);
444  data += (len + 2);
445  }
446  return 0;
447 }
448 
449 struct ast_aoc_decoded *ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan)
450 {
451  struct ast_aoc_decoded *decoded;
452 
453  /* verify our encoded payload is actually large enough to hold all the ies */
454  if ((size - (sizeof(struct ast_aoc_encoded)) != ntohs(encoded->datalen))) {
455  ast_log(LOG_WARNING, "Corrupted aoc encoded object, can not decode\n");
456  return NULL;
457  }
458 
459  if (!(decoded = ast_calloc(1, sizeof(struct ast_aoc_decoded)))) {
460  ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object \n");
461  return NULL;
462  }
463 
464  /* decode flags */
465 
467  decoded->msg_type = AST_AOC_S;
468  } else if (encoded->flags & AST_AOC_ENCODED_TYPE_E) {
469  decoded->msg_type = AST_AOC_E;
470  } else if (encoded->flags & AST_AOC_ENCODED_TYPE_D) {
471  decoded->msg_type = AST_AOC_D;
472  } else {
473  decoded->msg_type = AST_AOC_REQUEST;
474  }
475 
476  if (decoded->msg_type == AST_AOC_REQUEST) {
477  if (encoded->flags & AST_AOC_ENCODED_REQUEST_S) {
478  decoded->request_flag |= AST_AOC_REQUEST_S;
479  }
480  if (encoded->flags & AST_AOC_ENCODED_REQUEST_D) {
481  decoded->request_flag |= AST_AOC_REQUEST_D;
482  }
483  if (encoded->flags & AST_AOC_ENCODED_REQUEST_E) {
484  decoded->request_flag |= AST_AOC_REQUEST_E;
485  }
486  } else if ((decoded->msg_type == AST_AOC_D) || (decoded->msg_type == AST_AOC_E)) {
488  decoded->charge_type = AST_AOC_CHARGE_UNIT;
492  decoded->charge_type = AST_AOC_CHARGE_FREE;
493  } else {
494  decoded->charge_type = AST_AOC_CHARGE_NA;
495  }
496 
497  if (encoded->flags & AST_AOC_ENCODED_CHARGE_SUBTOTAL) {
498  decoded->total_type = AST_AOC_SUBTOTAL;
499  }
500  }
501 
502  /* decode information elements */
503  aoc_parse_ie(decoded, encoded->data, ntohs(encoded->datalen));
504 
505  if (aoc_debug_enabled) {
506  aoc_display_decoded_debug(decoded, 1, chan);
507  }
508 
509  return decoded;
510 }
511 
512 struct aoc_ie_data {
513  unsigned char buf[1024];
514  int pos;
515 };
516 
517 /*!
518  * \internal
519  * \brief append an AOC information element
520  * \note data is expected to already be in network byte order at this point
521  */
522 static int aoc_append_ie(struct aoc_ie_data *ied, unsigned short ie_id, const void *data, unsigned short datalen)
523 {
524  if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
525  ast_log(LOG_WARNING, "Failure to append AOC information element, out of space \n");
526  return -1;
527  }
528  ied->buf[ied->pos++] = ie_id;
529  ied->buf[ied->pos++] = datalen;
530  if (datalen) {
531  memcpy(ied->buf + ied->pos, data, datalen);
532  ied->pos += datalen;
533  }
534  return 0;
535 }
536 
538 {
539  ie->entry.charged_item = htons(entry->charged_item);
540  ie->entry.rate_type = htons(entry->rate_type);
541 
542  switch (entry->rate_type) {
544  ie->entry.rate.duration.multiplier = htons(entry->rate.duration.multiplier);
545  ie->entry.rate.duration.amount = htonl(entry->rate.duration.amount);
546  ie->entry.rate.duration.time = htonl(entry->rate.duration.time);
547  ie->entry.rate.duration.time_scale = htons(entry->rate.duration.time_scale);
550  ie->entry.rate.duration.charging_type = entry->rate.duration.charging_type; /* only one byte */
551 
554  entry->rate.duration.currency_name,
555  sizeof(ie->entry.rate.duration.currency_name));
556  }
557  break;
559  ie->entry.rate.flat.multiplier = htons(entry->rate.flat.multiplier);
560  ie->entry.rate.flat.amount = htonl(entry->rate.flat.amount);
561  if (!ast_strlen_zero(entry->rate.flat.currency_name)) {
563  entry->rate.flat.currency_name,
564  sizeof(ie->entry.rate.flat.currency_name));
565  }
566  break;
568  ie->entry.rate.volume.multiplier = htons(entry->rate.volume.multiplier);
569  ie->entry.rate.volume.amount = htonl(entry->rate.volume.amount);
570  ie->entry.rate.volume.volume_unit = htons(entry->rate.volume.volume_unit);
571  if (!ast_strlen_zero(entry->rate.volume.currency_name)) {
573  entry->rate.volume.currency_name,
574  sizeof(ie->entry.rate.volume.currency_name));
575  }
576  break;
578  ie->entry.rate.special_code = htons(entry->rate.special_code);
579  break;
580  }
581 
582 }
583 static void aoc_create_ie_data(struct ast_aoc_decoded *decoded, struct aoc_ie_data *ied)
584 {
585  ied->pos = 0;
586 
587  if (decoded->currency_amount) {
588  struct aoc_ie_currency ie = {
589  .amount = htonl(decoded->currency_amount),
590  .multiplier = decoded->multiplier, /* only one byte */
591  .name = { 0, },
592  };
593 
594  if (!ast_strlen_zero(decoded->currency_name)) {
595  ast_copy_string(ie.name, decoded->currency_name, sizeof(ie.name));
596  }
597 
598  aoc_append_ie(ied, AOC_IE_CURRENCY, (const void *) &ie, sizeof(ie));
599  }
600 
601  if (decoded->unit_count) {
602  struct aoc_ie_unit ie = { 0 };
603  int i;
604 
605  for (i = 0; i < decoded->unit_count; i++) {
606  ie.valid_amount = decoded->unit_list[i].valid_amount; /* only one byte */
607  ie.amount = htonl(decoded->unit_list[i].amount);
608  ie.valid_type = decoded->unit_list[i].valid_type; /* only one byte */
609  ie.type = decoded->unit_list[i].type; /* only one byte */
610  aoc_append_ie(ied, AOC_IE_UNIT, (const void *) &ie, sizeof(ie));
611  }
612  }
613 
614  if (decoded->billing_id) {
615  struct aoc_ie_billing ie;
616  ie.id = decoded->billing_id; /* only one byte */
617  aoc_append_ie(ied, AOC_IE_BILLING, (const void *) &ie, sizeof(ie));
618  }
619 
621  struct aoc_ie_charging_association ie;
622  memset(&ie, 0, sizeof(ie));
623  ie.ca.charging_type = decoded->charging_association.charging_type; /* only one byte */
625  ie.ca.charge.number.plan = decoded->charging_association.charge.number.plan; /* only one byte */
628  sizeof(ie.ca.charge.number.number));
630  ie.ca.charge.id = htonl(decoded->charging_association.charge.id);
631  }
632  aoc_append_ie(ied, AOC_IE_CHARGING_ASSOCIATION, (const void *) &ie, sizeof(ie));
633  }
634 
635  if (decoded->aoc_s_count) {
636  struct aoc_ie_charging_rate ie;
637  int i;
638  for (i = 0; i < decoded->aoc_s_count; i++) {
639  memset(&ie, 0, sizeof(ie));
641  aoc_append_ie(ied, AOC_IE_RATE, (const void *) &ie, sizeof(ie));
642  }
643  }
644 
645  if (decoded->termination_request) {
647  }
648 }
649 
650 struct ast_aoc_encoded *ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan)
651 {
652  struct aoc_ie_data ied;
653  struct ast_aoc_encoded *encoded = NULL;
654  size_t size = 0;
655 
656  if (!decoded || !out_size) {
657  return NULL;
658  }
659 
660  *out_size = 0;
661 
662  /* create information element buffer before allocating the payload,
663  * by doing this the exact size of the payload + the id data can be
664  * allocated all at once. */
665  aoc_create_ie_data(decoded, &ied);
666 
667  size = sizeof(struct ast_aoc_encoded) + ied.pos;
668 
669  if (!(encoded = ast_calloc(1, size))) {
670  ast_log(LOG_WARNING, "Failed to create ast_aoc_encoded object during decode routine. \n");
671  return NULL;
672  }
673 
674  /* -- Set ie data buffer */
675  if (ied.pos) {
676  /* this is safe because encoded was allocated to fit this perfectly */
677  memcpy(encoded->data, ied.buf, ied.pos);
678  encoded->datalen = htons(ied.pos);
679  }
680 
681  /* --- Set Flags --- */
682  switch (decoded->msg_type) {
683  case AST_AOC_S:
684  encoded->flags = AST_AOC_ENCODED_TYPE_S;
685  break;
686  case AST_AOC_D:
687  encoded->flags = AST_AOC_ENCODED_TYPE_D;
688  break;
689  case AST_AOC_E:
690  encoded->flags = AST_AOC_ENCODED_TYPE_E;
691  break;
692  case AST_AOC_REQUEST:
694  default:
695  break;
696  }
697 
698  /* if it is type request, set the types requested, else set charge type */
699  if (decoded->msg_type == AST_AOC_REQUEST) {
700  if (decoded->request_flag & AST_AOC_REQUEST_S) {
701  encoded->flags |= AST_AOC_ENCODED_REQUEST_S;
702  }
703  if (decoded->request_flag & AST_AOC_REQUEST_D) {
704  encoded->flags |= AST_AOC_ENCODED_REQUEST_D;
705  }
706  if (decoded->request_flag & AST_AOC_REQUEST_E) {
707  encoded->flags |= AST_AOC_ENCODED_REQUEST_E;
708  }
709  } else if ((decoded->msg_type == AST_AOC_D) || (decoded->msg_type == AST_AOC_E)) {
710  switch (decoded->charge_type) {
711  case AST_AOC_CHARGE_UNIT:
713  break;
716  break;
717  case AST_AOC_CHARGE_FREE:
719  case AST_AOC_CHARGE_NA:
720  default:
721  encoded->flags |= AST_AOC_ENCODED_CHARGE_NA;
722  break;
723  }
724 
725  if (decoded->total_type == AST_AOC_SUBTOTAL) {
727  }
728  }
729 
730  /* --- Set Version Number --- */
731  encoded->version = AST_AOC_ENCODE_VERSION;
732 
733  /* set the output size */
734  *out_size = size;
735 
736  if (aoc_debug_enabled) {
737  aoc_display_decoded_debug(decoded, 0, chan);
738  }
739 
740  return encoded;
741 }
742 
743 static int aoc_s_add_entry(struct ast_aoc_decoded *decoded, struct ast_aoc_s_entry *entry)
744 {
745  if (decoded->aoc_s_count >= ARRAY_LEN(decoded->aoc_s_entries)) {
746  return -1;
747  }
748 
749  decoded->aoc_s_entries[decoded->aoc_s_count] = *entry;
750  decoded->aoc_s_count++;
751 
752  return 0;
753 }
754 
755 
756 unsigned int ast_aoc_s_get_count(struct ast_aoc_decoded *decoded)
757 {
758  return decoded->aoc_s_count;
759 }
760 
761 const struct ast_aoc_s_entry *ast_aoc_s_get_rate_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
762 {
763  if (entry_number >= decoded->aoc_s_count) {
764  return NULL;
765  }
766 
767  return (const struct ast_aoc_s_entry *) &decoded->aoc_s_entries[entry_number];
768 }
769 
772  unsigned int amount,
773  enum ast_aoc_currency_multiplier multiplier,
774  const char *currency_name,
775  unsigned long time,
776  enum ast_aoc_time_scale time_scale,
777  unsigned long granularity_time,
778  enum ast_aoc_time_scale granularity_time_scale,
779  int step_function)
780 {
781 
782  struct ast_aoc_s_entry entry = { 0, };
783 
784  entry.charged_item = charged_item;
786  entry.rate.duration.amount = amount;
787  entry.rate.duration.multiplier = multiplier;
788  entry.rate.duration.time = time;
789  entry.rate.duration.time_scale = time_scale;
790  entry.rate.duration.granularity_time = granularity_time;
791  entry.rate.duration.granularity_time_scale = granularity_time_scale;
792  entry.rate.duration.charging_type = step_function ? 1 : 0;
793 
794  if (!ast_strlen_zero(currency_name)) {
795  ast_copy_string(entry.rate.duration.currency_name, currency_name, sizeof(entry.rate.duration.currency_name));
796  }
797 
798  return aoc_s_add_entry(decoded, &entry);
799 }
800 
803  unsigned int amount,
804  enum ast_aoc_currency_multiplier multiplier,
805  const char *currency_name)
806 {
807  struct ast_aoc_s_entry entry = { 0, };
808 
809  entry.charged_item = charged_item;
811  entry.rate.flat.amount = amount;
812  entry.rate.flat.multiplier = multiplier;
813 
814  if (!ast_strlen_zero(currency_name)) {
815  ast_copy_string(entry.rate.flat.currency_name, currency_name, sizeof(entry.rate.flat.currency_name));
816  }
817 
818  return aoc_s_add_entry(decoded, &entry);
819 }
820 
821 
824  enum ast_aoc_volume_unit volume_unit,
825  unsigned int amount,
826  enum ast_aoc_currency_multiplier multiplier,
827  const char *currency_name)
828 {
829  struct ast_aoc_s_entry entry = { 0, };
830 
831  entry.charged_item = charged_item;
833  entry.rate.volume.multiplier = multiplier;
834  entry.rate.volume.amount = amount;
835  entry.rate.volume.volume_unit = volume_unit;
836 
837  if (!ast_strlen_zero(currency_name)) {
838  ast_copy_string(entry.rate.volume.currency_name, currency_name, sizeof(entry.rate.volume.currency_name));
839  }
840 
841  return aoc_s_add_entry(decoded, &entry);
842 }
843 
846  unsigned int code)
847 {
848  struct ast_aoc_s_entry entry = { 0, };
849 
850  entry.charged_item = charged_item;
852  entry.rate.special_code = code;
853 
854  return aoc_s_add_entry(decoded, &entry);
855 }
856 
859  int from_beginning)
860 {
861  struct ast_aoc_s_entry entry = { 0, };
862 
863  entry.charged_item = charged_item;
865 
866  return aoc_s_add_entry(decoded, &entry);
867 }
868 
871 {
872  struct ast_aoc_s_entry entry = { 0, };
873 
874  entry.charged_item = charged_item;
876 
877  return aoc_s_add_entry(decoded, &entry);
878 }
879 
881  unsigned int code)
882 {
883  struct ast_aoc_s_entry entry = { 0, };
884 
887  entry.rate.special_code = code;
888 
889  return aoc_s_add_entry(decoded, &entry);
890 }
891 
893 {
894  return decoded->msg_type;
895 }
896 
898 {
899  return decoded->charge_type;
900 }
901 
903 {
904  return decoded->request_flag;
905 }
906 
908  const enum ast_aoc_total_type type)
909 {
910  decoded->total_type = type;
911  return 0;
912 }
913 
915 {
916  return decoded->total_type;
917 }
918 
920  const unsigned int amount,
921  const enum ast_aoc_currency_multiplier multiplier,
922  const char *name)
923 {
924 
925  if (!ast_strlen_zero(name)) {
926  ast_copy_string(decoded->currency_name, name, sizeof(decoded->currency_name));
927  }
928 
929  decoded->currency_amount = amount;
930 
931  if (multiplier && (multiplier < AST_AOC_MULT_NUM_ENTRIES)) {
932  decoded->multiplier = multiplier;
933  } else {
934  decoded->multiplier = AST_AOC_MULT_ONE;
935  }
936 
937  return 0;
938 }
939 
940 unsigned int ast_aoc_get_currency_amount(struct ast_aoc_decoded *decoded)
941 {
942  return decoded->currency_amount;
943 }
944 
946 {
947  return decoded->multiplier;
948 }
949 
951 {
952  switch (decoded->multiplier) {
954  return "0.001";
956  return "0.01";
958  return "0.1";
959  case AST_AOC_MULT_ONE:
960  return "1.0";
961  case AST_AOC_MULT_TEN:
962  return "10.0";
964  return "100.0";
966  return "1000.0";
967  default:
968  return "1.0";
969  }
970 }
971 
972 const char *ast_aoc_get_currency_name(struct ast_aoc_decoded *decoded)
973 {
974  return decoded->currency_name;
975 }
976 
978  const unsigned int amount_is_present,
979  const unsigned int amount,
980  const unsigned int type_is_present,
981  const unsigned int type)
982 {
983  if ((decoded->msg_type == AST_AOC_REQUEST) ||
984  (decoded->unit_count >= ARRAY_LEN(decoded->unit_list))) {
985  return -1;
986  }
987 
988  if (!amount_is_present && !type_is_present) {
989  return -1;
990  }
991 
992  decoded->unit_list[decoded->unit_count].valid_amount = amount_is_present;
993  if (amount_is_present) {
994  decoded->unit_list[decoded->unit_count].amount = amount;
995  } else {
996  decoded->unit_list[decoded->unit_count].amount = 0;
997  }
998 
999  decoded->unit_list[decoded->unit_count].valid_type = type_is_present;
1000  if (type_is_present) {
1001  decoded->unit_list[decoded->unit_count].type = type;
1002  } else {
1003  decoded->unit_list[decoded->unit_count].type = 0;
1004  }
1005  decoded->unit_count++;
1006 
1007  return 0;
1008 }
1009 
1010 const struct ast_aoc_unit_entry *ast_aoc_get_unit_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
1011 {
1012  if (entry_number >= decoded->unit_count) {
1013  return NULL;
1014  }
1015 
1016  return (const struct ast_aoc_unit_entry *) &decoded->unit_list[entry_number];
1017 }
1018 
1019 unsigned int ast_aoc_get_unit_count(struct ast_aoc_decoded *decoded)
1020 {
1021  return decoded->unit_count;
1022 }
1023 
1024 int ast_aoc_set_billing_id(struct ast_aoc_decoded *decoded, const enum ast_aoc_billing_id id)
1025 {
1026  if ((id >= AST_AOC_BILLING_NUM_ENTRIES) || (id < AST_AOC_BILLING_NA)) {
1027  return -1;
1028  }
1029 
1030  decoded->billing_id = id;
1031 
1032  return 0;
1033 }
1034 
1036 {
1037  return decoded->billing_id;
1038 }
1039 
1040 int ast_aoc_set_association_id(struct ast_aoc_decoded *decoded, const int id)
1041 {
1042  if (decoded->msg_type != AST_AOC_E) {
1043  return -1;
1044  }
1045  memset(&decoded->charging_association, 0, sizeof(decoded->charging_association));
1047  decoded->charging_association.charge.id = id;
1048  return 0;
1049 }
1050 
1052 {
1053  return &decoded->charging_association;
1054 }
1055 
1056 int ast_aoc_set_association_number(struct ast_aoc_decoded *decoded, const char *num, uint8_t plan)
1057 {
1058  if ((decoded->msg_type != AST_AOC_E) || ast_strlen_zero(num)) {
1059  return -1;
1060  }
1061  memset(&decoded->charging_association, 0, sizeof(decoded->charging_association));
1063  decoded->charging_association.charge.number.plan = plan;
1065 
1066  return 0;
1067 }
1068 
1070 {
1071  if (decoded->msg_type != AST_AOC_REQUEST) {
1072  return -1;
1073  }
1074  decoded->termination_request = 1;
1075 
1076  return 0;
1077 }
1078 
1080 {
1081  return decoded->termination_request;
1082 }
1083 
1084 /*!
1085  * \internal
1086  * \brief Convert AST_AOC_VOLUME_UNIT to string.
1087  * \since 1.8
1088  *
1089  * \param value Value to convert to string.
1090  *
1091  * \return String equivalent.
1092  */
1094 {
1095  const char *str;
1096 
1097  switch (value) {
1098  default:
1100  str = "Octet";
1101  break;
1103  str = "Segment";
1104  break;
1106  str = "Message";
1107  break;
1108  }
1109  return str;
1110 }
1111 
1112 /*!
1113  * \internal
1114  * \brief Convert ast_aoc_charged_item to string.
1115  * \since 1.8
1116  *
1117  * \param value Value to convert to string.
1118  *
1119  * \return String equivalent.
1120  */
1122 {
1123  const char *str;
1124 
1125  switch (value) {
1126  default:
1128  str = "NotAvailable";
1129  break;
1131  str = "SpecialArrangement";
1132  break;
1134  str = "BasicCommunication";
1135  break;
1137  str = "CallAttempt";
1138  break;
1140  str = "CallSetup";
1141  break;
1143  str = "UserUserInfo";
1144  break;
1146  str = "SupplementaryService";
1147  break;
1148  }
1149  return str;
1150 }
1151 
1152 /*!
1153  * \internal
1154  * \brief Convert ast_aoc_total_type to string.
1155  * \since 1.8
1156  *
1157  * \param value Value to convert to string.
1158  *
1159  * \return String equivalent.
1160  */
1162 {
1163  const char *str;
1164 
1165  switch (value) {
1166  default:
1167  case AST_AOC_SUBTOTAL:
1168  str = "SubTotal";
1169  break;
1170  case AST_AOC_TOTAL:
1171  str = "Total";
1172  break;
1173  }
1174  return str;
1175 }
1176 
1177 /*!
1178  * \internal
1179  * \brief Convert ast_aoc_rate_type to string.
1180  * \since 1.8
1181  *
1182  * \param value Value to convert to string.
1183  *
1184  * \return String equivalent.
1185  */
1187 {
1188  const char *str;
1189 
1190  switch (value) {
1191  default:
1192  case AST_AOC_RATE_TYPE_NA:
1193  str = "NotAvailable";
1194  break;
1196  str = "Free";
1197  break;
1199  str = "FreeFromBeginning";
1200  break;
1202  str = "Duration";
1203  break;
1205  str = "Flat";
1206  break;
1208  str = "Volume";
1209  break;
1211  str = "SpecialCode";
1212  break;
1213  }
1214  return str;
1215 }
1216 
1217 /*!
1218  * \internal
1219  * \brief Convert AST_AOC_TIME_SCALE to string.
1220  * \since 1.8
1221  *
1222  * \param value Value to convert to string.
1223  *
1224  * \return String equivalent.
1225  */
1226 static const char *aoc_scale_str(enum ast_aoc_time_scale value)
1227 {
1228  const char *str;
1229 
1230  switch (value) {
1231  default:
1233  str = "OneHundredthSecond";
1234  break;
1236  str = "OneTenthSecond";
1237  break;
1239  str = "Second";
1240  break;
1242  str = "TenSeconds";
1243  break;
1245  str = "Minute";
1246  break;
1248  str = "Hour";
1249  break;
1251  str = "Day";
1252  break;
1253  }
1254  return str;
1255 }
1256 
1258 {
1259  const char *str;
1260 
1261  switch (value) {
1262  default:
1263  case AST_AOC_CHARGE_NA:
1264  str = "NotAvailable";
1265  break;
1266  case AST_AOC_CHARGE_FREE:
1267  str = "Free";
1268  break;
1270  str = "Currency";
1271  break;
1272  case AST_AOC_CHARGE_UNIT:
1273  str = "Units";
1274  break;
1275  }
1276 
1277  return str;
1278 }
1279 
1281 {
1282  switch (mult) {
1284  return "1/1000";
1286  return "1/100";
1287  case AST_AOC_MULT_ONETENTH:
1288  return "1/10";
1289  case AST_AOC_MULT_ONE:
1290  return "1";
1291  case AST_AOC_MULT_TEN:
1292  return "10";
1293  case AST_AOC_MULT_HUNDRED:
1294  return "100";
1295  case AST_AOC_MULT_THOUSAND:
1296  return "1000";
1298  break;
1299  }
1300  return "1";
1301 }
1302 
1303 static const char *aoc_billingid_str(enum ast_aoc_billing_id billing_id)
1304 {
1305  switch (billing_id) {
1307  return "Normal";
1309  return "Reverse";
1311  return "CreditCard";
1313  return "CallForwardingUnconditional";
1315  return "CallForwardingBusy";
1317  return "CallForwardingNoReply";
1319  return "CallDeflection";
1321  return "CallTransfer";
1322  case AST_AOC_BILLING_NA:
1323  return "NotAvailable";
1325  break;
1326  }
1327  return "NotAvailable";
1328 }
1329 
1331 {
1332  struct ast_aoc_decoded *new_decoded = NULL;
1333  struct ast_aoc_encoded *encoded = NULL;
1334  size_t size;
1335  int res = 0;
1336 
1337  if (!(encoded = ast_aoc_encode(decoded, &size, NULL))) {
1338  return -1;
1339  }
1340 
1341  if (!(new_decoded = ast_aoc_decode(encoded, size, NULL))) {
1342  ast_free(encoded);
1343  return -1;
1344  }
1345 
1346  if (memcmp(new_decoded, decoded, sizeof(struct ast_aoc_decoded))) {
1347  res = -1;
1348  }
1349 
1350  ast_aoc_destroy_decoded(new_decoded);
1351  ast_aoc_destroy_encoded(encoded);
1352  return res;
1353 }
1354 
1355 static char *aoc_cli_debug_enable(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1356 {
1357  switch (cmd) {
1358  case CLI_INIT:
1359  e->command = "aoc set debug";
1360  e->usage =
1361  "Usage: 'aoc set debug on' to enable aoc debug, 'aoc set debug off' to disable debug.\n";
1362  return NULL;
1363  case CLI_GENERATE:
1364  return NULL;
1365  case CLI_HANDLER:
1366  if (a->argc != 4) {
1367  return CLI_SHOWUSAGE;
1368  } else if(ast_true(a->argv[3])) {
1369  ast_cli(a->fd, "aoc debug enabled\n");
1370  aoc_debug_enabled = 1;
1371  } else if (ast_false(a->argv[3])) {
1372  ast_cli(a->fd, "aoc debug disabled\n");
1373  aoc_debug_enabled = 0;
1374  } else {
1375  return CLI_SHOWUSAGE;
1376  }
1377  }
1378 
1379  return CLI_SUCCESS;
1380 }
1381 
1382 /*!
1383  * \internal
1384  * \brief Append the time structure to the event message string.
1385  * \since 1.8
1386  *
1387  * \param msg Event message string being built.
1388  * \param prefix Prefix to add to the amount lines.
1389  * \param name Name of the time structure to convert.
1390  * \param time Data to convert.
1391  * \param scale Data to convert.
1392  *
1393  * \return Nothing
1394  */
1395 static void aoc_time_str(struct ast_str **msg, const char *prefix, const char *name, unsigned long time, enum ast_aoc_time_scale scale)
1396 {
1397  ast_str_append(msg, 0, "%s/%s/Length: %lu\r\n", prefix, name, time);
1398  ast_str_append(msg, 0, "%s/%s/Scale: %s\r\n", prefix, name,
1399  aoc_scale_str(scale));
1400 }
1401 
1402 /*!
1403  * \internal
1404  * \brief Append the amount structure to the event message string.
1405  * \since 1.8
1406  *
1407  * \param msg Event message string being built.
1408  * \param prefix Prefix to add to the amount lines.
1409  * \param amount Data to convert.
1410  * \param multipler to convert
1411  *
1412  * \return Nothing
1413  */
1414 static void aoc_amount_str(struct ast_str **msg, const char *prefix, unsigned int amount, enum ast_aoc_currency_multiplier mult)
1415 {
1416  static const char name[] = "Amount";
1417 
1418  ast_str_append(msg, 0, "%s/%s/Cost: %u\r\n", prefix, name, amount);
1419  ast_str_append(msg, 0, "%s/%s/Multiplier: %s\r\n", prefix, name,
1420  aoc_multiplier_str(mult));
1421 }
1422 
1423 static void aoc_request_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
1424 {
1425  if (decoded->request_flag) {
1426  ast_str_append(msg, 0, "AOCRequest:");
1427  if (decoded->request_flag & AST_AOC_REQUEST_S) {
1428  ast_str_append(msg, 0, "S");
1429  }
1430  if (decoded->request_flag & AST_AOC_REQUEST_D) {
1431  ast_str_append(msg, 0, "D");
1432  }
1433  if (decoded->request_flag & AST_AOC_REQUEST_E) {
1434  ast_str_append(msg, 0, "E");
1435  }
1436  ast_str_append(msg, 0, "\r\n");
1437 
1438  } else {
1439  ast_str_append(msg, 0, "AOCRequest: NONE\r\n");
1440  }
1441 }
1442 
1443 static void aoc_s_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
1444 {
1445  const char *rate_str;
1446  char prefix[32];
1447  int idx;
1448 
1449  ast_str_append(msg, 0, "NumberRates: %d\r\n", decoded->aoc_s_count);
1450  for (idx = 0; idx < decoded->aoc_s_count; ++idx) {
1451  snprintf(prefix, sizeof(prefix), "Rate(%d)", idx);
1452 
1453  ast_str_append(msg, 0, "%s/Chargeable: %s\r\n", prefix,
1455  if (decoded->aoc_s_entries[idx].charged_item == AST_AOC_CHARGED_ITEM_NA) {
1456  continue;
1457  }
1458  rate_str = aoc_rate_type_str(decoded->aoc_s_entries[idx].rate_type);
1459  ast_str_append(msg, 0, "%s/Type: %s\r\n", prefix, rate_str);
1460  switch (decoded->aoc_s_entries[idx].rate_type) {
1462  strcat(prefix, "/");
1463  strcat(prefix, rate_str);
1464  ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
1465  decoded->aoc_s_entries[idx].rate.duration.currency_name);
1466  aoc_amount_str(msg, prefix,
1467  decoded->aoc_s_entries[idx].rate.duration.amount,
1468  decoded->aoc_s_entries[idx].rate.duration.multiplier);
1469  ast_str_append(msg, 0, "%s/ChargingType: %s\r\n", prefix,
1470  decoded->aoc_s_entries[idx].rate.duration.charging_type ?
1471  "StepFunction" : "ContinuousCharging");
1472  aoc_time_str(msg, prefix, "Time",
1473  decoded->aoc_s_entries[idx].rate.duration.time,
1474  decoded->aoc_s_entries[idx].rate.duration.time_scale);
1475  if (decoded->aoc_s_entries[idx].rate.duration.granularity_time) {
1476  aoc_time_str(msg, prefix, "Granularity",
1479  }
1480  break;
1482  strcat(prefix, "/");
1483  strcat(prefix, rate_str);
1484  ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
1485  decoded->aoc_s_entries[idx].rate.flat.currency_name);
1486  aoc_amount_str(msg, prefix,
1487  decoded->aoc_s_entries[idx].rate.flat.amount,
1488  decoded->aoc_s_entries[idx].rate.flat.multiplier);
1489  break;
1491  strcat(prefix, "/");
1492  strcat(prefix, rate_str);
1493  ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
1494  decoded->aoc_s_entries[idx].rate.volume.currency_name);
1495  aoc_amount_str(msg, prefix,
1496  decoded->aoc_s_entries[idx].rate.volume.amount,
1497  decoded->aoc_s_entries[idx].rate.volume.multiplier);
1498  ast_str_append(msg, 0, "%s/Unit: %s\r\n", prefix,
1500  break;
1502  ast_str_append(msg, 0, "%s/%s: %d\r\n", prefix, rate_str,
1503  decoded->aoc_s_entries[idx].rate.special_code);
1504  break;
1505  default:
1506  break;
1507  }
1508  }
1509 }
1510 
1511 static void aoc_d_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
1512 {
1513  const char *charge_str;
1514  int idx;
1515  char prefix[32];
1516 
1517  charge_str = aoc_charge_type_str(decoded->charge_type);
1518  ast_str_append(msg, 0, "Type: %s\r\n", charge_str);
1519 
1520  switch (decoded->charge_type) {
1522  case AST_AOC_CHARGE_UNIT:
1523  ast_str_append(msg, 0, "BillingID: %s\r\n",
1524  aoc_billingid_str(decoded->billing_id));
1525  ast_str_append(msg, 0, "TypeOfCharging: %s\r\n",
1527  break;
1528  default:
1529  break;
1530  }
1531 
1532  switch (decoded->charge_type) {
1534  ast_str_append(msg, 0, "%s: %s\r\n", charge_str,
1535  decoded->currency_name);
1536  aoc_amount_str(msg, charge_str,
1537  decoded->currency_amount,
1538  decoded->multiplier);
1539  break;
1540  case AST_AOC_CHARGE_UNIT:
1541  ast_str_append(msg, 0, "%s/NumberItems: %d\r\n", charge_str,
1542  decoded->unit_count);
1543  for (idx = 0; idx < decoded->unit_count; ++idx) {
1544  snprintf(prefix, sizeof(prefix), "%s/Item(%d)", charge_str, idx);
1545  if (decoded->unit_list[idx].valid_amount) {
1546  ast_str_append(msg, 0, "%s/NumberOf: %u\r\n", prefix,
1547  decoded->unit_list[idx].amount);
1548  }
1549  if (decoded->unit_list[idx].valid_type) {
1550  ast_str_append(msg, 0, "%s/TypeOf: %u\r\n", prefix,
1551  decoded->unit_list[idx].type);
1552  }
1553  }
1554  break;
1555  default:
1556  break;
1557  }
1558 }
1559 
1560 static void aoc_e_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
1561 {
1562  const char *charge_str;
1563  int idx;
1564  char prefix[32];
1565 
1566  charge_str = "ChargingAssociation";
1567 
1568  switch (decoded->charging_association.charging_type) {
1570  snprintf(prefix, sizeof(prefix), "%s/Number", charge_str);
1571  ast_str_append(msg, 0, "%s: %s\r\n", prefix,
1573  ast_str_append(msg, 0, "%s/Plan: %d\r\n", prefix,
1575  break;
1577  ast_str_append(msg, 0, "%s/ID: %d\r\n", charge_str, decoded->charging_association.charge.id);
1578  break;
1580  default:
1581  break;
1582  }
1583 
1584  charge_str = aoc_charge_type_str(decoded->charge_type);
1585  ast_str_append(msg, 0, "Type: %s\r\n", charge_str);
1586  switch (decoded->charge_type) {
1588  case AST_AOC_CHARGE_UNIT:
1589  ast_str_append(msg, 0, "BillingID: %s\r\n",
1590  aoc_billingid_str(decoded->billing_id));
1591  break;
1592  default:
1593  break;
1594  }
1595  switch (decoded->charge_type) {
1597  ast_str_append(msg, 0, "%s: %s\r\n", charge_str,
1598  decoded->currency_name);
1599  aoc_amount_str(msg, charge_str,
1600  decoded->currency_amount,
1601  decoded->multiplier);
1602  break;
1603  case AST_AOC_CHARGE_UNIT:
1604  ast_str_append(msg, 0, "%s/NumberItems: %d\r\n", charge_str,
1605  decoded->unit_count);
1606  for (idx = 0; idx < decoded->unit_count; ++idx) {
1607  snprintf(prefix, sizeof(prefix), "%s/Item(%d)", charge_str, idx);
1608  if (decoded->unit_list[idx].valid_amount) {
1609  ast_str_append(msg, 0, "%s/NumberOf: %u\r\n", prefix,
1610  decoded->unit_list[idx].amount);
1611  }
1612  if (decoded->unit_list[idx].valid_type) {
1613  ast_str_append(msg, 0, "%s/TypeOf: %u\r\n", prefix,
1614  decoded->unit_list[idx].type);
1615  }
1616  }
1617  break;
1618  default:
1619  break;
1620  }
1621 }
1622 
1623 static struct ast_json *units_to_json(const struct ast_aoc_decoded *decoded)
1624 {
1625  int i;
1626  struct ast_json *units = ast_json_array_create();
1627 
1628  if (!units) {
1629  return ast_json_null();
1630  }
1631 
1632  for (i = 0; i < decoded->unit_count; ++i) {
1633  struct ast_json *unit = ast_json_object_create();
1634 
1635  if (decoded->unit_list[i].valid_amount) {
1637  unit, "NumberOf", ast_json_stringf(
1638  "%u", decoded->unit_list[i].amount));
1639  }
1640 
1641  if (decoded->unit_list[i].valid_type) {
1643  unit, "TypeOf", ast_json_stringf(
1644  "%u", decoded->unit_list[i].type));
1645  }
1646 
1647  if (ast_json_array_append(units, unit)) {
1648  break;
1649  }
1650  }
1651 
1652  return units;
1653 }
1654 
1655 static struct ast_json *currency_to_json(const char *name, int cost,
1656  enum ast_aoc_currency_multiplier mult)
1657 {
1658  return ast_json_pack("{s:s, s:i, s:s}",
1659  "Name", AST_JSON_UTF8_VALIDATE(name),
1660  "Cost", cost,
1661  "Multiplier", aoc_multiplier_str(mult));
1662 }
1663 
1664 static struct ast_json *charge_to_json(const struct ast_aoc_decoded *decoded)
1665 {
1666  struct ast_json *obj;
1667  const char *obj_type;
1668 
1669  if (decoded->charge_type != AST_AOC_CHARGE_CURRENCY &&
1670  decoded->charge_type != AST_AOC_CHARGE_UNIT) {
1671  return ast_json_pack("{s:s}",
1672  "Type", aoc_charge_type_str(decoded->charge_type));
1673  }
1674 
1675  if (decoded->charge_type == AST_AOC_CHARGE_CURRENCY) {
1676  obj_type = "Currency";
1677  obj = currency_to_json(decoded->currency_name, decoded->currency_amount,
1678  decoded->multiplier);
1679  } else { /* decoded->charge_type == AST_AOC_CHARGE_UNIT */
1680  obj_type = "Units";
1681  obj = units_to_json(decoded);
1682  }
1683 
1684  return ast_json_pack("{s:s, s:s, s:s, s:o}",
1685  "Type", aoc_charge_type_str(decoded->charge_type),
1686  "BillingID", aoc_billingid_str(decoded->billing_id),
1687  "TotalType", aoc_type_of_totaling_str(decoded->total_type),
1688  obj_type, obj);
1689 }
1690 
1691 static struct ast_json *association_to_json(const struct ast_aoc_decoded *decoded)
1692 {
1693  switch (decoded->charging_association.charging_type) {
1695  return ast_json_pack("{s:s, s:i}",
1697  "Plan", decoded->charging_association.charge.number.plan);
1699  return ast_json_pack("{s:i}", "ID", decoded->charging_association.charge.id);
1701  default:
1702  return ast_json_null();
1703  }
1704 }
1705 
1706 static struct ast_json *s_to_json(const struct ast_aoc_decoded *decoded)
1707 {
1708  int i;
1709  struct ast_json *rates = ast_json_array_create();
1710 
1711  if (!rates) {
1712  return ast_json_null();
1713  }
1714 
1715  for (i = 0; i < decoded->aoc_s_count; ++i) {
1716  struct ast_json *rate;
1717  struct ast_json *type = NULL;
1718  struct ast_json *currency;
1719  const char *charge_item = aoc_charged_item_str(
1720  decoded->aoc_s_entries[i].charged_item);
1721 
1722  if (decoded->aoc_s_entries[i].charged_item == AST_AOC_CHARGED_ITEM_NA) {
1723  rate = ast_json_pack("{s:s}", "Chargeable", charge_item);
1724  if (ast_json_array_append(rates, rate)) {
1725  break;
1726  }
1727  continue;
1728  }
1729 
1730  switch (decoded->aoc_s_entries[i].rate_type) {
1732  {
1733  struct ast_json *time;
1734  struct ast_json *granularity = NULL;
1735 
1736  currency = currency_to_json(
1738  decoded->aoc_s_entries[i].rate.duration.amount,
1739  decoded->aoc_s_entries[i].rate.duration.multiplier);
1740 
1741  time = ast_json_pack("{s:I, s:i}",
1742  "Length", (ast_json_int_t)decoded->aoc_s_entries[i].rate.duration.time,
1743  "Scale", decoded->aoc_s_entries[i].rate.duration.time_scale);
1744 
1745  if (decoded->aoc_s_entries[i].rate.duration.granularity_time) {
1746  granularity = ast_json_pack("{s:I, s:i}",
1748  "Scale", decoded->aoc_s_entries[i].rate.duration.granularity_time_scale);
1749  }
1750 
1751  type = ast_json_pack("{s:o, s:s, s:o, s:o}",
1752  "Currency", currency,
1753  "ChargingType", decoded->aoc_s_entries[i].rate.duration.charging_type
1754  ? "StepFunction" : "ContinuousCharging",
1755  "Time", time,
1756  "Granularity", granularity ?: ast_json_null());
1757 
1758  break;
1759  }
1761  currency = currency_to_json(
1762  decoded->aoc_s_entries[i].rate.flat.currency_name,
1763  decoded->aoc_s_entries[i].rate.flat.amount,
1764  decoded->aoc_s_entries[i].rate.flat.multiplier);
1765 
1766  type = ast_json_pack("{s:o}", "Currency", currency);
1767  break;
1769  currency = currency_to_json(
1770  decoded->aoc_s_entries[i].rate.volume.currency_name,
1771  decoded->aoc_s_entries[i].rate.volume.amount,
1772  decoded->aoc_s_entries[i].rate.volume.multiplier);
1773 
1774  type = ast_json_pack("{s:s, s:o}",
1775  "Unit", aoc_volume_unit_str(
1776  decoded->aoc_s_entries[i].rate.volume.volume_unit),
1777  "Currency", currency);
1778  break;
1780  type = ast_json_pack("{s:i}",
1781  "SpecialCode", decoded->aoc_s_entries[i].rate.special_code);
1782  break;
1783  default:
1784  break;
1785  }
1786 
1787  rate = ast_json_pack("{s:s, s:o}",
1788  "Chargeable", charge_item,
1789  aoc_rate_type_str(decoded->aoc_s_entries[i].rate_type), type);
1790  if (ast_json_array_append(rates, rate)) {
1791  break;
1792  }
1793  }
1794  return rates;
1795 }
1796 
1797 static struct ast_json *d_to_json(const struct ast_aoc_decoded *decoded)
1798 {
1799  return ast_json_pack("{s:o}", "Charge", charge_to_json(decoded));
1800 }
1801 
1802 static struct ast_json *e_to_json(const struct ast_aoc_decoded *decoded)
1803 {
1804  return ast_json_pack("{s:o, s:o}",
1805  "ChargingAssociation", association_to_json(decoded),
1806  "Charge", charge_to_json(decoded));
1807 }
1808 
1810  /*! Channel AOC event is associated with (NULL for unassociated) */
1812  /*! AOC JSON blob of data */
1813  struct ast_json *blob;
1814 };
1815 
1816 static void aoc_event_blob_dtor(void *obj)
1817 {
1818  struct aoc_event_blob *aoc_event = obj;
1819 
1820  ao2_cleanup(aoc_event->snapshot);
1821  ast_json_unref(aoc_event->blob);
1822 }
1823 
1824 /*!
1825  * \internal
1826  * \brief Publish an AOC event.
1827  * \since 13.3.0
1828  *
1829  * \param chan Channel associated with the AOC event. (May be NULL if no channel)
1830  * \param msg_type What kind of AOC event.
1831  * \param blob AOC data blob to publish.
1832  *
1833  * \return Nothing
1834  */
1835 static void aoc_publish_blob(struct ast_channel *chan, struct stasis_message_type *msg_type, struct ast_json *blob)
1836 {
1837  struct stasis_message *msg;
1838  struct aoc_event_blob *aoc_event;
1839 
1840  if (!blob || ast_json_is_null(blob)) {
1841  /* No AOC blob information? Nothing to send an event about. */
1842  return;
1843  }
1844 
1845  aoc_event = ao2_alloc_options(sizeof(*aoc_event), aoc_event_blob_dtor,
1847  if (!aoc_event) {
1848  return;
1849  }
1850 
1851  if (chan) {
1852  ast_channel_lock(chan);
1853  aoc_event->snapshot = ao2_bump(ast_channel_snapshot(chan));
1854  ast_channel_unlock(chan);
1855  if (!aoc_event->snapshot) {
1856  ao2_ref(aoc_event, -1);
1857  return;
1858  }
1859  }
1860  aoc_event->blob = ast_json_ref(blob);
1861 
1862  msg = stasis_message_create(msg_type, aoc_event);
1863  ao2_ref(aoc_event, -1);
1864 
1865  if (msg) {
1867  ao2_ref(msg, -1);
1868  }
1869 }
1870 
1872  const char *event_name)
1873 {
1874  struct aoc_event_blob *aoc_event = stasis_message_data(message);
1875  struct ast_str *channel = NULL;
1876  struct ast_str *aoc;
1877  struct ast_manager_event_blob *ev = NULL;
1878 
1879  if (aoc_event->snapshot) {
1880  channel = ast_manager_build_channel_state_string(aoc_event->snapshot);
1881  if (!channel) {
1882  return NULL;
1883  }
1884  }
1885 
1886  aoc = ast_manager_str_from_json_object(aoc_event->blob, NULL);
1887  if (aoc && !ast_strlen_zero(ast_str_buffer(aoc))) {
1888  ev = ast_manager_event_blob_create(EVENT_FLAG_AOC, event_name, "%s%s",
1889  AS_OR(channel, ""), ast_str_buffer(aoc));
1890  }
1891 
1892  ast_free(aoc);
1893  ast_free(channel);
1894  return ev;
1895 }
1896 
1898 {
1899  return aoc_to_ami(message, "AOC-S");
1900 }
1901 
1903 {
1904  return aoc_to_ami(message, "AOC-D");
1905 }
1906 
1908 {
1909  return aoc_to_ami(message, "AOC-E");
1910 }
1911 
1912 struct stasis_message_type *aoc_s_type(void);
1913 struct stasis_message_type *aoc_d_type(void);
1914 struct stasis_message_type *aoc_e_type(void);
1915 
1917  aoc_s_type,
1918  .to_ami = aoc_s_to_ami);
1919 
1921  aoc_d_type,
1922  .to_ami = aoc_d_to_ami);
1923 
1925  aoc_e_type,
1926  .to_ami = aoc_e_to_ami);
1927 
1928 int ast_aoc_manager_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan)
1929 {
1930  struct ast_json *blob;
1931  struct stasis_message_type *msg_type;
1932 
1933  if (!decoded) {
1934  return -1;
1935  }
1936 
1937  switch (decoded->msg_type) {
1938  case AST_AOC_S:
1939  blob = s_to_json(decoded);
1940  msg_type = aoc_s_type();
1941  break;
1942  case AST_AOC_D:
1943  blob = d_to_json(decoded);
1944  msg_type = aoc_d_type();
1945  break;
1946  case AST_AOC_E:
1947  blob = e_to_json(decoded);
1948  msg_type = aoc_e_type();
1949  break;
1950  default:
1951  /* events for AST_AOC_REQUEST are not generated here */
1952  return 0;
1953  }
1954 
1955  aoc_publish_blob(chan, msg_type, blob);
1956  ast_json_unref(blob);
1957  return 0;
1958 }
1959 
1960 int ast_aoc_decoded2str(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
1961 {
1962  if (!decoded || !msg) {
1963  return -1;
1964  }
1965 
1966  switch (decoded->msg_type) {
1967  case AST_AOC_S:
1968  ast_str_append(msg, 0, "AOC-S\r\n");
1969  aoc_s_event(decoded, msg);
1970  break;
1971  case AST_AOC_D:
1972  ast_str_append(msg, 0, "AOC-D\r\n");
1973  aoc_d_event(decoded, msg);
1974  break;
1975  case AST_AOC_E:
1976  ast_str_append(msg, 0, "AOC-E\r\n");
1977  aoc_e_event(decoded, msg);
1978  break;
1979  case AST_AOC_REQUEST:
1980  ast_str_append(msg, 0, "AOC-Request\r\n");
1981  aoc_request_event(decoded, msg);
1982  break;
1983  }
1984 
1985  return 0;
1986 }
1987 
1988 static void aoc_display_decoded_debug(const struct ast_aoc_decoded *decoded, int decoding, struct ast_channel *chan)
1989 {
1990  struct ast_str *msg;
1991 
1992  if (!decoded || !(msg = ast_str_create(1024))) {
1993  return;
1994  }
1995 
1996  if (decoding) {
1997  ast_str_append(&msg, 0, "---- DECODED AOC MSG ----\r\n");
1998  } else {
1999  ast_str_append(&msg, 0, "---- ENCODED AOC MSG ----\r\n");
2000  }
2001  if (chan) {
2002  ast_str_append(&msg, 0, "CHANNEL: %s\r\n", ast_channel_name(chan));
2003  }
2004 
2005  if (ast_aoc_decoded2str(decoded, &msg)) {
2006  ast_free(msg);
2007  return;
2008  }
2009 
2010  ast_verb(1, "%s\r\n", ast_str_buffer(msg));
2011  ast_free(msg);
2012 }
2013 
2014 static struct ast_cli_entry aoc_cli[] = {
2015  AST_CLI_DEFINE(aoc_cli_debug_enable, "enable cli debugging of AOC messages"),
2016 };
2017 
2018 static void aoc_shutdown(void)
2019 {
2020  STASIS_MESSAGE_TYPE_CLEANUP(aoc_s_type);
2021  STASIS_MESSAGE_TYPE_CLEANUP(aoc_d_type);
2022  STASIS_MESSAGE_TYPE_CLEANUP(aoc_e_type);
2023 
2024  ast_cli_unregister_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
2025 }
2027 {
2028  STASIS_MESSAGE_TYPE_INIT(aoc_s_type);
2029  STASIS_MESSAGE_TYPE_INIT(aoc_d_type);
2030  STASIS_MESSAGE_TYPE_INIT(aoc_e_type);
2031 
2033  return ast_cli_register_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
2034 }
struct stasis_message_type * aoc_s_type(void)
uint16_t volume_unit
Definition: aoc.h:134
static const char type[]
Definition: chan_ooh323.c:109
Struct containing info for an AMI event to send out.
Definition: manager.h:491
#define ast_channel_lock(chan)
Definition: channel.h:2890
char valid_amount
Definition: aoc.h:179
Main Channel structure associated with a channel.
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
static void aoc_shutdown(void)
Definition: aoc.c:2018
static void aoc_create_ie_data_charging_rate(const struct ast_aoc_s_entry *entry, struct aoc_ie_charging_rate *ie)
Definition: aoc.c:537
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
uint16_t datalen
Definition: aoc.c:200
ast_aoc_request
Definition: aoc.h:76
static void aoc_amount_str(struct ast_str **msg, const char *prefix, unsigned int amount, enum ast_aoc_currency_multiplier mult)
Definition: aoc.c:1414
#define AST_AOC_ENCODED_REQUEST_E
Definition: aoc.c:179
Asterisk main include file. File version handling, generic pbx functions.
ast_aoc_volume_unit
Definition: aoc.h:125
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static struct ast_json * e_to_json(const struct ast_aoc_decoded *decoded)
Definition: aoc.c:1802
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
static int aoc_s_add_entry(struct ast_aoc_decoded *decoded, struct ast_aoc_s_entry *entry)
Definition: aoc.c:743
uint32_t amount
Definition: aoc.c:252
enum ast_aoc_type ast_aoc_get_msg_type(struct ast_aoc_decoded *decoded)
get the message type, AOC-D, AOC-E, or AOC Request
Definition: aoc.c:892
String manipulation functions.
union ast_aoc_charging_association::@215 charge
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
void * ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
free an ast_aoc_encoded object
Definition: aoc.c:313
const struct ast_aoc_s_entry * ast_aoc_s_get_rate_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
get a specific AOC-S rate entry.
Definition: aoc.c:761
#define AST_AOC_ENCODED_TYPE_E
Definition: aoc.c:174
static struct ast_json * charge_to_json(const struct ast_aoc_decoded *decoded)
Definition: aoc.c:1664
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
unsigned int ast_aoc_get_unit_count(struct ast_aoc_decoded *decoded)
get the number of unit entries for AOC-D and AOC-E messages
Definition: aoc.c:1019
#define AST_AOC_ENCODED_CHARGE_FREE
Definition: aoc.c:182
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
enum ast_aoc_currency_multiplier multiplier
Definition: aoc.c:212
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1501
static struct requests requests
struct ast_aoc_duration_rate duration
Definition: aoc.h:171
static struct ast_json * currency_to_json(const char *name, int cost, enum ast_aoc_currency_multiplier mult)
Definition: aoc.c:1655
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
#define LOG_WARNING
Definition: logger.h:274
int ast_aoc_test_encode_decode_match(struct ast_aoc_decoded *decoded)
test aoc encode decode routines.
Definition: aoc.c:1330
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static void aoc_parse_ie_charging_rate(struct ast_aoc_decoded *decoded, const struct aoc_ie_charging_rate *ie)
Definition: aoc.c:319
enum ast_aoc_charge_type ast_aoc_get_charge_type(struct ast_aoc_decoded *decoded)
get the charging type for an AOC-D or AOC-E message
Definition: aoc.c:897
#define AST_AOC_ENCODED_TYPE_D
Definition: aoc.c:173
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition: json.h:87
struct ast_channel_snapshot * ast_channel_snapshot(const struct ast_channel *chan)
uint8_t version
Definition: aoc.c:198
Definition: aoc.h:165
uint32_t amount
Definition: aoc.h:132
uint8_t datalen
Definition: aoc.c:247
#define AST_AOC_ENCODED_CHARGE_CURRENCY
Definition: aoc.c:183
unsigned int type
Definition: aoc.h:182
Structure representing a snapshot of channel state.
static void aoc_e_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
Definition: aoc.c:1560
static const char * aoc_billingid_str(enum ast_aoc_billing_id billing_id)
Definition: aoc.c:1303
struct ast_aoc_charging_association_number number
Definition: aoc.h:197
static struct ast_manager_event_blob * aoc_s_to_ami(struct stasis_message *message)
Definition: aoc.c:1897
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1523
Definition: cli.h:152
int ast_aoc_decoded2str(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
Convert decoded aoc msg to string representation.
Definition: aoc.c:1960
struct ast_json * ast_json_stringf(const char *format,...)
Create a JSON string, printf style.
Definition: json.c:283
AOC_IE
AOC Payload Information Elements.
Definition: aoc.c:235
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
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
struct stasis_message_type * aoc_d_type(void)
static void aoc_event_blob_dtor(void *obj)
Definition: aoc.c:1816
#define AST_AOC_ENCODED_REQUEST_S
Definition: aoc.c:177
#define EVENT_FLAG_AOC
Definition: manager.h:87
uint16_t charged_item
Definition: aoc.h:166
int ast_aoc_set_association_id(struct ast_aoc_decoded *decoded, const int id)
set the charging association id for an AST_AOC_E message
Definition: aoc.c:1040
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
uint8_t charging_type
Charging interval type.
Definition: aoc.h:122
Definition: muted.c:95
static const char * aoc_type_of_totaling_str(enum ast_aoc_total_type value)
Definition: aoc.c:1161
uint8_t type
Definition: aoc.c:261
int ast_aoc_set_total_type(struct ast_aoc_decoded *decoded, const enum ast_aoc_total_type type)
Sets the type of total for a AOC-D message.
Definition: aoc.c:907
static struct ast_json * association_to_json(const struct ast_aoc_decoded *decoded)
Definition: aoc.c:1691
static const char * aoc_charged_item_str(enum ast_aoc_s_charged_item value)
Definition: aoc.c:1121
ast_aoc_currency_multiplier
Defines the currency multiplier for an aoc message.
Definition: aoc.h:34
const char * str
Definition: app_jack.c:147
enum ast_aoc_currency_multiplier ast_aoc_get_currency_multiplier(struct ast_aoc_decoded *decoded)
get the currency multiplier for AOC-D and AOC-E messages
Definition: aoc.c:945
static const char * aoc_volume_unit_str(enum ast_aoc_volume_unit value)
Definition: aoc.c:1093
static const char * aoc_multiplier_str(enum ast_aoc_currency_multiplier mult)
Definition: aoc.c:1280
enum ast_aoc_billing_id billing_id
Definition: aoc.c:221
ast_aoc_time_scale
Definition: aoc.h:87
#define NULL
Definition: resample.c:96
uint32_t amount
Definition: aoc.h:104
int ast_json_is_null(const struct ast_json *value)
Check if value is JSON null.
Definition: json.c:263
int value
Definition: syslog.c:37
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
int ast_aoc_set_termination_request(struct ast_aoc_decoded *decoded)
Mark the AST_AOC_REQUEST message as a termination request.
Definition: aoc.c:1069
uint8_t valid_amount
Definition: aoc.c:260
const char * ast_aoc_get_currency_name(struct ast_aoc_decoded *decoded)
get the currency name for AOC-D and AOC-E messages
Definition: aoc.c:972
uint8_t ie_id
Definition: aoc.c:246
ast_aoc_total_type
Definition: aoc.h:82
#define ast_verb(level,...)
Definition: logger.h:455
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:9727
int ast_aoc_add_unit_entry(struct ast_aoc_decoded *decoded, const unsigned int amount_is_present, const unsigned int amount, const unsigned int type_is_present, const unsigned int type)
Adds a unit entry into the list of units.
Definition: aoc.c:977
struct ast_json * blob
Definition: aoc.c:1813
int ast_aoc_s_add_special_arrangement(struct ast_aoc_decoded *decoded, unsigned int code)
Add AOC-S special arrangement entry.
Definition: aoc.c:880
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition: json.c:404
Utility functions.
int pos
Definition: aoc.c:514
uint16_t multiplier
Definition: aoc.h:109
struct ast_str * ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
Convert a JSON object into an AMI compatible string.
Definition: manager.c:1821
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition: json.c:248
#define ao2_bump(obj)
Definition: astobj2.h:491
enum ast_aoc_total_type total_type
Definition: aoc.c:209
const struct ast_aoc_unit_entry * ast_aoc_get_unit_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
get a specific unit entry.
Definition: aoc.c:1010
struct ast_channel_snapshot * snapshot
Definition: aoc.c:1811
static void aoc_display_decoded_debug(const struct ast_aoc_decoded *decoded, int decoding, struct ast_channel *chan)
Definition: aoc.c:1988
static struct ast_cli_entry aoc_cli[]
Definition: aoc.c:2014
static struct ast_manager_event_blob * aoc_d_to_ami(struct stasis_message *message)
Definition: aoc.c:1902
int ast_aoc_set_currency_info(struct ast_aoc_decoded *decoded, const unsigned int amount, const enum ast_aoc_currency_multiplier multiplier, const char *name)
Sets the currency values for a AOC-D or AOC-E message.
Definition: aoc.c:919
static char * aoc_cli_debug_enable(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: aoc.c:1355
const struct ast_aoc_charging_association * ast_aoc_get_association_info(struct ast_aoc_decoded *decoded)
get the charging association info for AOC-E messages
Definition: aoc.c:1051
#define ast_log
Definition: astobj2.c:42
#define AST_AOC_ENCODED_CHARGE_UNIT
Definition: aoc.c:184
Generic Advice of Charge encode and decode routines.
static const char * aoc_rate_type_str(enum ast_aoc_s_rate_type value)
Definition: aoc.c:1186
uint16_t special_code
Definition: aoc.h:174
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
enum ast_aoc_billing_id ast_aoc_get_billing_id(struct ast_aoc_decoded *decoded)
get the billing id for AOC-D and AOC-E messages
Definition: aoc.c:1035
ast_aoc_s_charged_item
Definition: aoc.h:145
const int fd
Definition: cli.h:159
struct ast_aoc_charging_association charging_association
Definition: aoc.c:224
static void aoc_publish_blob(struct ast_channel *chan, struct stasis_message_type *msg_type, struct ast_json *blob)
Definition: aoc.c:1835
#define ao2_ref(o, delta)
Definition: astobj2.h:464
int unit_count
Definition: aoc.c:217
int ast_aoc_s_add_rate_special_charge_code(struct ast_aoc_decoded *decoded, enum ast_aoc_s_charged_item charged_item, unsigned int code)
Add AOC-S special rate entry.
Definition: aoc.c:844
struct ast_aoc_flat_rate flat
Definition: aoc.h:172
char currency_name[AOC_CURRENCY_NAME_SIZE]
Definition: aoc.h:142
#define AST_AOC_ENCODED_CHARGE_SUBTOTAL
Definition: aoc.c:186
uint16_t multiplier
Definition: aoc.h:140
ast_aoc_charge_type
Definition: aoc.h:69
int ast_aoc_manager_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan)
generate AOC manager event for an AOC-S, AOC-D, or AOC-E msg
Definition: aoc.c:1928
int aoc_s_count
Definition: aoc.c:227
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
struct ast_aoc_decoded * ast_aoc_create(const enum ast_aoc_type msg_type, const enum ast_aoc_charge_type charge_type, const enum ast_aoc_request requests)
creates a ast_aoc_decode object of a specific message type
Definition: aoc.c:276
uint16_t multiplier
Definition: aoc.h:133
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
Definition: json.c:352
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition: json.c:368
char currency_name[AOC_CURRENCY_NAME_SIZE]
Definition: aoc.c:214
const char *const * argv
Definition: cli.h:161
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
uint16_t time_scale
Definition: aoc.h:110
static struct ast_json * s_to_json(const struct ast_aoc_decoded *decoded)
Definition: aoc.c:1706
ast_aoc_type
Definition: aoc.h:62
#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:1822
static char aoc_debug_enabled
Definition: aoc.c:192
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
struct ast_aoc_volume_rate volume
Definition: aoc.h:173
#define AST_AOC_ENCODED_TYPE_REQUEST
Definition: aoc.c:172
uint8_t flags
Definition: aoc.c:199
#define CLI_SHOWUSAGE
Definition: cli.h:45
int ast_aoc_set_association_number(struct ast_aoc_decoded *decoded, const char *num, uint8_t plan)
set the charging accociation number for an AOC-E message
Definition: aoc.c:1056
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.
uint32_t amount
Definition: aoc.c:258
static struct ast_manager_event_blob * aoc_e_to_ami(struct stasis_message *message)
Definition: aoc.c:1907
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
struct ast_aoc_unit_entry unit_list[32]
Definition: aoc.c:218
unsigned int currency_amount
Definition: aoc.c:213
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:307
STASIS_MESSAGE_TYPE_DEFN(aoc_s_type,.to_ami=aoc_s_to_ami)
#define AST_AOC_ENCODED_REQUEST_D
Definition: aoc.c:178
struct ast_aoc_decoded * ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan)
decodes an encoded aoc payload.
Definition: aoc.c:449
static struct ast_json * d_to_json(const struct ast_aoc_decoded *decoded)
Definition: aoc.c:1797
uint32_t granularity_time
Definition: aoc.h:107
#define ast_strlen_zero(a)
Definition: muted.c:73
#define ast_channel_unlock(chan)
Definition: channel.h:2891
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1507
static struct ast_json * units_to_json(const struct ast_aoc_decoded *decoded)
Definition: aoc.c:1623
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
int ast_aoc_s_add_rate_na(struct ast_aoc_decoded *decoded, enum ast_aoc_s_charged_item charged_item)
Add AOC-S entry indicating charge item is not available.
Definition: aoc.c:869
struct ast_aoc_encoded * ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan)
encodes a decoded aoc structure so it can be passed on the wire
Definition: aoc.c:650
uint8_t valid_type
Definition: aoc.c:259
static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
enum ast_aoc_request ast_aoc_get_request(struct ast_aoc_decoded *decoded)
get the types of AOC requested for when message type is AOC Request
Definition: aoc.c:902
static struct ast_manager_event_blob * aoc_to_ami(struct stasis_message *message, const char *event_name)
Definition: aoc.c:1871
Prototypes for public functions only of internal interest,.
static const char * aoc_scale_str(enum ast_aoc_time_scale value)
Definition: aoc.c:1226
char currency_name[AOC_CURRENCY_NAME_SIZE]
Definition: aoc.h:114
const char * ast_aoc_get_currency_multiplier_decimal(struct ast_aoc_decoded *decoded)
get the currency multiplier for AOC-D and AOC-E messages in decimal format
Definition: aoc.c:950
char valid_type
Definition: aoc.h:181
union ast_aoc_s_entry::@214 rate
Charge rate being applied.
ast_aoc_s_rate_type
Definition: aoc.h:155
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:1720
static void aoc_time_str(struct ast_str **msg, const char *prefix, const char *name, unsigned long time, enum ast_aoc_time_scale scale)
Definition: aoc.c:1395
AOC IE payload header.
Definition: aoc.c:245
int ast_aoc_cli_init(void)
enable aoc cli options
Definition: aoc.c:2026
const char * usage
Definition: cli.h:177
unsigned int ast_aoc_get_currency_amount(struct ast_aoc_decoded *decoded)
get the currency amount for AOC-D and AOC-E messages
Definition: aoc.c:940
int ast_aoc_s_add_rate_flat(struct ast_aoc_decoded *decoded, enum ast_aoc_s_charged_item charged_item, unsigned int amount, enum ast_aoc_currency_multiplier multiplier, const char *currency_name)
Add AOC-S flat rate entry.
Definition: aoc.c:801
uint8_t multiplier
Definition: aoc.c:253
#define CLI_SUCCESS
Definition: cli.h:44
struct ast_json * ast_json_object_create(void)
Create a new JSON object.
Definition: json.c:389
unsigned char buf[1024]
Definition: aoc.c:513
uint32_t time
Definition: aoc.h:105
#define AS_OR(a, b)
Definition: strings.h:49
enum ast_aoc_type msg_type
Definition: aoc.c:206
static void aoc_s_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
Definition: aoc.c:1443
unsigned int ast_aoc_s_get_count(struct ast_aoc_decoded *decoded)
get the number rates associated with an AOC-S message
Definition: aoc.c:756
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Standard Command Line Interface.
struct ast_aoc_charging_association ca
Definition: aoc.c:269
enum ast_aoc_total_type ast_aoc_get_total_type(struct ast_aoc_decoded *decoded)
get the type of total for a AOC-D message
Definition: aoc.c:914
#define AST_AOC_ENCODE_VERSION
Definition: aoc.c:189
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
int ast_aoc_s_add_rate_duration(struct ast_aoc_decoded *decoded, enum ast_aoc_s_charged_item charged_item, unsigned int amount, enum ast_aoc_currency_multiplier multiplier, const char *currency_name, unsigned long time, enum ast_aoc_time_scale time_scale, unsigned long granularity_time, enum ast_aoc_time_scale granularity_time_scale, int step_function)
Add AOC-S duration rate entry.
Definition: aoc.c:770
static void aoc_d_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
Definition: aoc.c:1511
const char * ast_channel_name(const struct ast_channel *chan)
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1839
#define AOC_CURRENCY_NAME_SIZE
Definition: aoc.h:31
static void aoc_request_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
Definition: aoc.c:1423
ast_aoc_billing_id
Defines the billing id options for an aoc message.
Definition: aoc.h:49
struct stasis_message_type * aoc_e_type(void)
unsigned char data[0]
Definition: aoc.c:201
#define AST_AOC_ENCODED_CHARGE_NA
Definition: aoc.c:181
struct ast_aoc_s_entry entry
Definition: aoc.c:273
Abstract JSON element (object, array, string, int, ...).
Definition: aoc.h:64
Definition: aoc.h:66
enum ast_aoc_request request_flag
Definition: aoc.c:208
char name[AOC_CURRENCY_NAME_SIZE]
Definition: aoc.c:254
Definition: search.h:40
uint8_t id
Definition: aoc.c:265
int ast_aoc_get_termination_request(struct ast_aoc_decoded *decoded)
get whether or not the AST_AOC_REQUEST message as a termination request.
Definition: aoc.c:1079
enum queue_result id
Definition: app_queue.c:1510
uint32_t amount
Definition: aoc.h:139
struct ast_aoc_s_entry aoc_s_entries[10]
Definition: aoc.c:228
int ast_aoc_s_add_rate_volume(struct ast_aoc_decoded *decoded, enum ast_aoc_s_charged_item charged_item, enum ast_aoc_volume_unit volume_unit, unsigned int amount, enum ast_aoc_currency_multiplier multiplier, const char *currency_name)
Add AOC-S volume rate entry.
Definition: aoc.c:822
static void aoc_create_ie_data(struct ast_aoc_decoded *decoded, struct aoc_ie_data *ied)
Definition: aoc.c:583
Definition: aoc.h:178
int ast_aoc_s_add_rate_free(struct ast_aoc_decoded *decoded, enum ast_aoc_s_charged_item charged_item, int from_beginning)
Add AOC-S indicating charge item is free.
Definition: aoc.c:857
static int aoc_append_ie(struct aoc_ie_data *ied, unsigned short ie_id, const void *data, unsigned short datalen)
Definition: aoc.c:522
uint16_t rate_type
Definition: aoc.h:167
static const char * aoc_charge_type_str(enum ast_aoc_charge_type value)
Definition: aoc.c:1257
#define AST_AOC_ENCODED_TYPE_S
Definition: aoc.c:175
enum ast_aoc_charge_type charge_type
Definition: aoc.c:207
char termination_request
Definition: aoc.c:231
unsigned int amount
Definition: aoc.h:180
static int aoc_parse_ie(struct ast_aoc_decoded *decoded, unsigned char *data, unsigned int datalen)
Definition: aoc.c:369
#define AST_JSON_UTF8_VALIDATE(str)
Check str for UTF-8 and replace with an empty string if fails the check.
Definition: json.h:224
uint16_t granularity_time_scale
Definition: aoc.h:111
Definition: aoc.h:65
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
static char prefix[MAX_PREFIX]
Definition: http.c:141
int ast_aoc_set_billing_id(struct ast_aoc_decoded *decoded, const enum ast_aoc_billing_id id)
set the billing id for a AOC-D or AST_AOC_E message
Definition: aoc.c:1024
char currency_name[AOC_CURRENCY_NAME_SIZE]
Definition: aoc.h:135
static struct test_val a