Wed Jan 8 2020 09:49:39

Asterisk developer's documentation


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 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413586 $");
32 
33 #include "asterisk/aoc.h"
34 #include "asterisk/utils.h"
35 #include "asterisk/strings.h"
36 #include "asterisk/_private.h"
37 #include "asterisk/cli.h"
38 #include "asterisk/manager.h"
39 
40 /* Encoded Payload Flags */
41 #define AST_AOC_ENCODED_TYPE_REQUEST (0 << 0)
42 #define AST_AOC_ENCODED_TYPE_D (1 << 0)
43 #define AST_AOC_ENCODED_TYPE_E (2 << 0)
44 #define AST_AOC_ENCODED_TYPE_S (3 << 0)
45 
46 #define AST_AOC_ENCODED_REQUEST_S (1 << 2)
47 #define AST_AOC_ENCODED_REQUEST_D (1 << 3)
48 #define AST_AOC_ENCODED_REQUEST_E (1 << 4)
49 
50 #define AST_AOC_ENCODED_CHARGE_NA (0 << 5)
51 #define AST_AOC_ENCODED_CHARGE_FREE (1 << 5)
52 #define AST_AOC_ENCODED_CHARGE_CURRENCY (2 << 5)
53 #define AST_AOC_ENCODED_CHARGE_UNIT (3 << 5)
54 
55 #define AST_AOC_ENCODED_CHARGE_SUBTOTAL (1 << 7)
56 #define AST_AOC_ENCODED_CHARGE_TOTAL (0 << 7)
57 
58 #define AST_AOC_ENCODE_VERSION 1
59 
60 
61 static char aoc_debug_enabled = 0;
62 static void aoc_display_decoded_debug(const struct ast_aoc_decoded *decoded, int decoding, struct ast_channel *chan);
63 static int aoc_s_add_entry(struct ast_aoc_decoded *decoded, struct ast_aoc_s_entry *entry);
64 
65 /* AOC Payload Header. Holds all the encoded AOC data to pass on the wire */
67  uint8_t version;
68  uint8_t flags;
69  uint16_t datalen;
70  unsigned char data[0];
71 };
72 
73 /* Decoded AOC data */
79 
80  /* currency information */
82  unsigned int currency_amount;
84 
85  /* unit information */
88 
89  /* Billing Id */
91 
92  /* Charging Association information */
94 
95  /* AOC-S charge information */
98 
99  /* Is this an AOC Termination Request */
101 };
102 
103 /*! \brief AOC Payload Information Elements */
104 enum AOC_IE {
111 };
112 
113 /*! \brief AOC IE payload header */
115  uint8_t ie_id;
116  uint8_t datalen;
117  char data[0];
118 } __attribute__((packed));
119 
121  uint32_t amount;
122  uint8_t multiplier;
124 } __attribute__((packed));
125 
126 struct aoc_ie_unit {
127  uint32_t amount;
128  uint8_t valid_type;
129  uint8_t valid_amount;
130  uint8_t type;
131 } __attribute__((packed));
132 
134  uint8_t id;
135 } __attribute__((packed));
136 
139 } __attribute__((packed));
140 
143 } __attribute__((packed));
144 
146  const enum ast_aoc_charge_type charge_type,
147  const enum ast_aoc_request requests)
148 {
149  struct ast_aoc_decoded *decoded = NULL;
150 
151  /* verify input */
152  if (((unsigned int) charge_type > AST_AOC_CHARGE_UNIT) ||
153  ((unsigned int) msg_type > AST_AOC_E) ||
154  ((msg_type == AST_AOC_REQUEST) && !requests)) {
155 
156  ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object, invalid input\n");
157  return NULL;
158  }
159 
160  if (!(decoded = ast_calloc(1, sizeof(struct ast_aoc_decoded)))) {
161  ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object \n");
162  return NULL;
163  }
164 
165  decoded->msg_type = msg_type;
166 
167  if (msg_type == AST_AOC_REQUEST) {
168  decoded->request_flag = requests;
169  } else if ((msg_type == AST_AOC_D) || (msg_type == AST_AOC_E)) {
170  decoded->charge_type = charge_type;
171  }
172 
173  return decoded;
174 }
175 
177 {
178  ast_free(decoded);
179  return NULL;
180 }
181 
183 {
184  ast_free(encoded);
185  return NULL;
186 }
187 
188 static void aoc_parse_ie_charging_rate(struct ast_aoc_decoded *decoded, const struct aoc_ie_charging_rate *ie)
189 {
190  struct ast_aoc_s_entry entry = { 0, };
191 
192  entry.charged_item = ntohs(ie->entry.charged_item);
193  entry.rate_type = ntohs(ie->entry.rate_type);
194 
195  switch (entry.rate_type) {
197  entry.rate.duration.multiplier = ntohs(ie->entry.rate.duration.multiplier);
198  entry.rate.duration.amount = ntohl(ie->entry.rate.duration.amount);
199  entry.rate.duration.time = ntohl(ie->entry.rate.duration.time);
200  entry.rate.duration.time_scale = ntohs(ie->entry.rate.duration.time_scale);
203  entry.rate.duration.charging_type = ie->entry.rate.duration.charging_type; /* only one byte */
204 
208  sizeof(entry.rate.duration.currency_name));
209  }
210  break;
212  entry.rate.flat.multiplier = ntohs(ie->entry.rate.flat.multiplier);
213  entry.rate.flat.amount = ntohl(ie->entry.rate.flat.amount);
217  sizeof(entry.rate.flat.currency_name));
218  }
219  break;
221  entry.rate.volume.multiplier = ntohs(ie->entry.rate.volume.multiplier);
222  entry.rate.volume.amount = ntohl(ie->entry.rate.volume.amount);
223  entry.rate.volume.volume_unit = ntohs(ie->entry.rate.volume.volume_unit);
227  sizeof(entry.rate.volume.currency_name));
228  }
229  break;
231  entry.rate.special_code = ntohs(ie->entry.rate.special_code);
232  break;
233  }
234 
235  aoc_s_add_entry(decoded, &entry);
236 }
237 
238 static int aoc_parse_ie(struct ast_aoc_decoded *decoded, unsigned char *data, unsigned int datalen)
239 {
240  enum AOC_IE ie_id;
241  unsigned int len;
242 
243  while (datalen >= 2) {
244  ie_id = data[0];
245  len = data[1];
246  if (len > datalen -2) {
247  ast_log(LOG_ERROR, "AOC information element length exceeds the total message size\n");
248  return -1;
249  }
250 
251  switch(ie_id) {
252  case AOC_IE_CURRENCY:
253  if (len == sizeof(struct aoc_ie_currency)) {
254  struct aoc_ie_currency ie;
255  memcpy(&ie, data + 2, len);
256  decoded->currency_amount = ntohl(ie.amount);
257  decoded->multiplier = ie.multiplier; /* only one byte */
258  memcpy(decoded->currency_name, ie.name, sizeof(decoded->currency_name));
259  } else {
260  ast_log(LOG_WARNING, "Received invalid currency ie\n");
261  }
262  break;
263  case AOC_IE_UNIT:
264  if (len == sizeof(struct aoc_ie_unit)) {
265  struct aoc_ie_unit ie;
266  memcpy(&ie, data + 2, len);
267  ast_aoc_add_unit_entry(decoded, ie.valid_amount, ntohl(ie.amount), ie.valid_type, ie.type);
268  } else {
269  ast_log(LOG_WARNING, "Received invalid unit ie\n");
270  }
271  break;
272  case AOC_IE_BILLING:
273  if (len == sizeof(struct aoc_ie_billing)) {
274  struct aoc_ie_billing ie;
275  memcpy(&ie, data + 2, len);
276  decoded->billing_id = ie.id; /* only one byte */
277  } else {
278  ast_log(LOG_WARNING, "Received invalid billing ie\n");
279  }
280  break;
282  if (len == sizeof(struct aoc_ie_charging_association)) {
283  memcpy(&decoded->charging_association, data + 2, sizeof(decoded->charging_association));
284  /* everything in the charging_association struct is a single byte except for the id */
286  decoded->charging_association.charge.id = ntohl(decoded->charging_association.charge.id);
287  }
288  } else {
289  ast_log(LOG_WARNING, "Received invalid charging association ie\n");
290  }
291  break;
292  case AOC_IE_RATE:
293  if (len == sizeof(struct aoc_ie_charging_rate)) {
294  struct aoc_ie_charging_rate ie;
295  memcpy(&ie, data + 2, len);
296  aoc_parse_ie_charging_rate(decoded, &ie);
297  } else {
298  ast_log(LOG_WARNING, "Received invalid charging rate ie\n");
299  }
300  break;
302  if (len == 0) {
303  decoded->termination_request = 1;
304  } else {
305  ast_log(LOG_WARNING, "Received invalid termination request ie\n");
306  }
307  break;
308  default:
309  ast_log(LOG_WARNING, "Unknown AOC Information Element, ignoring.\n");
310  }
311 
312  datalen -= (len + 2);
313  data += (len + 2);
314  }
315  return 0;
316 }
317 
318 struct ast_aoc_decoded *ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan)
319 {
320  struct ast_aoc_decoded *decoded;
321 
322  /* verify our encoded payload is actually large enough to hold all the ies */
323  if ((size - (sizeof(struct ast_aoc_encoded)) != ntohs(encoded->datalen))) {
324  ast_log(LOG_WARNING, "Corrupted aoc encoded object, can not decode\n");
325  return NULL;
326  }
327 
328  if (!(decoded = ast_calloc(1, sizeof(struct ast_aoc_decoded)))) {
329  ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object \n");
330  return NULL;
331  }
332 
333  /* decode flags */
334 
336  decoded->msg_type = AST_AOC_S;
337  } else if (encoded->flags & AST_AOC_ENCODED_TYPE_E) {
338  decoded->msg_type = AST_AOC_E;
339  } else if (encoded->flags & AST_AOC_ENCODED_TYPE_D) {
340  decoded->msg_type = AST_AOC_D;
341  } else {
342  decoded->msg_type = AST_AOC_REQUEST;
343  }
344 
345  if (decoded->msg_type == AST_AOC_REQUEST) {
346  if (encoded->flags & AST_AOC_ENCODED_REQUEST_S) {
347  decoded->request_flag |= AST_AOC_REQUEST_S;
348  }
349  if (encoded->flags & AST_AOC_ENCODED_REQUEST_D) {
350  decoded->request_flag |= AST_AOC_REQUEST_D;
351  }
352  if (encoded->flags & AST_AOC_ENCODED_REQUEST_E) {
353  decoded->request_flag |= AST_AOC_REQUEST_E;
354  }
355  } else if ((decoded->msg_type == AST_AOC_D) || (decoded->msg_type == AST_AOC_E)) {
357  decoded->charge_type = AST_AOC_CHARGE_UNIT;
361  decoded->charge_type = AST_AOC_CHARGE_FREE;
362  } else {
363  decoded->charge_type = AST_AOC_CHARGE_NA;
364  }
365 
366  if (encoded->flags & AST_AOC_ENCODED_CHARGE_SUBTOTAL) {
367  decoded->total_type = AST_AOC_SUBTOTAL;
368  }
369  }
370 
371  /* decode information elements */
372  aoc_parse_ie(decoded, encoded->data, ntohs(encoded->datalen));
373 
374  if (aoc_debug_enabled) {
375  aoc_display_decoded_debug(decoded, 1, chan);
376  }
377 
378  return decoded;
379 }
380 
381 struct aoc_ie_data {
382  unsigned char buf[1024];
383  int pos;
384 };
385 
386 /*!
387  * \internal
388  * \brief append an AOC information element
389  * \note data is expected to already be in network byte order at this point
390  */
391 static int aoc_append_ie(struct aoc_ie_data *ied, unsigned short ie_id, const void *data, unsigned short datalen)
392 {
393  if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
394  ast_log(LOG_WARNING, "Failure to append AOC information element, out of space \n");
395  return -1;
396  }
397  ied->buf[ied->pos++] = ie_id;
398  ied->buf[ied->pos++] = datalen;
399  if (datalen) {
400  memcpy(ied->buf + ied->pos, data, datalen);
401  ied->pos += datalen;
402  }
403  return 0;
404 }
405 
406 static void aoc_create_ie_data_charging_rate(const struct ast_aoc_s_entry *entry, struct aoc_ie_charging_rate *ie)
407 {
408  ie->entry.charged_item = htons(entry->charged_item);
409  ie->entry.rate_type = htons(entry->rate_type);
410 
411  switch (entry->rate_type) {
413  ie->entry.rate.duration.multiplier = htons(entry->rate.duration.multiplier);
414  ie->entry.rate.duration.amount = htonl(entry->rate.duration.amount);
415  ie->entry.rate.duration.time = htonl(entry->rate.duration.time);
416  ie->entry.rate.duration.time_scale = htons(entry->rate.duration.time_scale);
419  ie->entry.rate.duration.charging_type = entry->rate.duration.charging_type; /* only one byte */
420 
423  entry->rate.duration.currency_name,
424  sizeof(ie->entry.rate.duration.currency_name));
425  }
426  break;
428  ie->entry.rate.flat.multiplier = htons(entry->rate.flat.multiplier);
429  ie->entry.rate.flat.amount = htonl(entry->rate.flat.amount);
430  if (!ast_strlen_zero(entry->rate.flat.currency_name)) {
432  entry->rate.flat.currency_name,
433  sizeof(ie->entry.rate.flat.currency_name));
434  }
435  break;
437  ie->entry.rate.volume.multiplier = htons(entry->rate.volume.multiplier);
438  ie->entry.rate.volume.amount = htonl(entry->rate.volume.amount);
439  ie->entry.rate.volume.volume_unit = htons(entry->rate.volume.volume_unit);
440  if (!ast_strlen_zero(entry->rate.volume.currency_name)) {
442  entry->rate.volume.currency_name,
443  sizeof(ie->entry.rate.volume.currency_name));
444  }
445  break;
447  ie->entry.rate.special_code = htons(entry->rate.special_code);
448  break;
449  }
450 
451 }
452 static void aoc_create_ie_data(struct ast_aoc_decoded *decoded, struct aoc_ie_data *ied)
453 {
454  ied->pos = 0;
455 
456  if (decoded->currency_amount) {
457  struct aoc_ie_currency ie = {
458  .amount = htonl(decoded->currency_amount),
459  .multiplier = decoded->multiplier, /* only one byte */
460  .name = { 0, },
461  };
462 
463  if (!ast_strlen_zero(decoded->currency_name)) {
464  ast_copy_string(ie.name, decoded->currency_name, sizeof(ie.name));
465  }
466 
467  aoc_append_ie(ied, AOC_IE_CURRENCY, (const void *) &ie, sizeof(ie));
468  }
469 
470  if (decoded->unit_count) {
471  struct aoc_ie_unit ie = { 0 };
472  int i;
473 
474  for (i = 0; i < decoded->unit_count; i++) {
475  ie.valid_amount = decoded->unit_list[i].valid_amount; /* only one byte */
476  ie.amount = htonl(decoded->unit_list[i].amount);
477  ie.valid_type = decoded->unit_list[i].valid_type; /* only one byte */
478  ie.type = decoded->unit_list[i].type; /* only one byte */
479  aoc_append_ie(ied, AOC_IE_UNIT, (const void *) &ie, sizeof(ie));
480  }
481  }
482 
483  if (decoded->billing_id) {
484  struct aoc_ie_billing ie;
485  ie.id = decoded->billing_id; /* only one byte */
486  aoc_append_ie(ied, AOC_IE_BILLING, (const void *) &ie, sizeof(ie));
487  }
488 
490  struct aoc_ie_charging_association ie;
491  memset(&ie, 0, sizeof(ie));
492  ie.ca.charging_type = decoded->charging_association.charging_type; /* only one byte */
494  ie.ca.charge.number.plan = decoded->charging_association.charge.number.plan; /* only one byte */
497  sizeof(ie.ca.charge.number.number));
499  ie.ca.charge.id = htonl(decoded->charging_association.charge.id);
500  }
501  aoc_append_ie(ied, AOC_IE_CHARGING_ASSOCIATION, (const void *) &ie, sizeof(ie));
502  }
503 
504  if (decoded->aoc_s_count) {
505  struct aoc_ie_charging_rate ie;
506  int i;
507  for (i = 0; i < decoded->aoc_s_count; i++) {
508  memset(&ie, 0, sizeof(ie));
510  aoc_append_ie(ied, AOC_IE_RATE, (const void *) &ie, sizeof(ie));
511  }
512  }
513 
514  if (decoded->termination_request) {
516  }
517 }
518 
519 struct ast_aoc_encoded *ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan)
520 {
521  struct aoc_ie_data ied;
522  struct ast_aoc_encoded *encoded = NULL;
523  size_t size = 0;
524 
525  if (!decoded || !out_size) {
526  return NULL;
527  }
528 
529  *out_size = 0;
530 
531  /* create information element buffer before allocating the payload,
532  * by doing this the exact size of the payload + the id data can be
533  * allocated all at once. */
534  aoc_create_ie_data(decoded, &ied);
535 
536  size = sizeof(struct ast_aoc_encoded) + ied.pos;
537 
538  if (!(encoded = ast_calloc(1, size))) {
539  ast_log(LOG_WARNING, "Failed to create ast_aoc_encoded object during decode routine. \n");
540  return NULL;
541  }
542 
543  /* -- Set ie data buffer */
544  if (ied.pos) {
545  /* this is safe because encoded was allocated to fit this perfectly */
546  memcpy(encoded->data, ied.buf, ied.pos);
547  encoded->datalen = htons(ied.pos);
548  }
549 
550  /* --- Set Flags --- */
551  switch (decoded->msg_type) {
552  case AST_AOC_S:
553  encoded->flags = AST_AOC_ENCODED_TYPE_S;
554  break;
555  case AST_AOC_D:
556  encoded->flags = AST_AOC_ENCODED_TYPE_D;
557  break;
558  case AST_AOC_E:
559  encoded->flags = AST_AOC_ENCODED_TYPE_E;
560  break;
561  case AST_AOC_REQUEST:
563  default:
564  break;
565  }
566 
567  /* if it is type request, set the types requested, else set charge type */
568  if (decoded->msg_type == AST_AOC_REQUEST) {
569  if (decoded->request_flag & AST_AOC_REQUEST_S) {
570  encoded->flags |= AST_AOC_ENCODED_REQUEST_S;
571  }
572  if (decoded->request_flag & AST_AOC_REQUEST_D) {
573  encoded->flags |= AST_AOC_ENCODED_REQUEST_D;
574  }
575  if (decoded->request_flag & AST_AOC_REQUEST_E) {
576  encoded->flags |= AST_AOC_ENCODED_REQUEST_E;
577  }
578  } else if ((decoded->msg_type == AST_AOC_D) || (decoded->msg_type == AST_AOC_E)) {
579  switch (decoded->charge_type) {
580  case AST_AOC_CHARGE_UNIT:
582  break;
585  break;
586  case AST_AOC_CHARGE_FREE:
588  case AST_AOC_CHARGE_NA:
589  default:
590  encoded->flags |= AST_AOC_ENCODED_CHARGE_NA;
591  break;
592  }
593 
594  if (decoded->total_type == AST_AOC_SUBTOTAL) {
596  }
597  }
598 
599  /* --- Set Version Number --- */
600  encoded->version = AST_AOC_ENCODE_VERSION;
601 
602  /* set the output size */
603  *out_size = size;
604 
605  if (aoc_debug_enabled) {
606  aoc_display_decoded_debug(decoded, 0, chan);
607  }
608 
609  return encoded;
610 }
611 
612 static int aoc_s_add_entry(struct ast_aoc_decoded *decoded, struct ast_aoc_s_entry *entry)
613 {
614  if (decoded->aoc_s_count >= ARRAY_LEN(decoded->aoc_s_entries)) {
615  return -1;
616  }
617 
618  decoded->aoc_s_entries[decoded->aoc_s_count] = *entry;
619  decoded->aoc_s_count++;
620 
621  return 0;
622 }
623 
624 
625 unsigned int ast_aoc_s_get_count(struct ast_aoc_decoded *decoded)
626 {
627  return decoded->aoc_s_count;
628 }
629 
630 const struct ast_aoc_s_entry *ast_aoc_s_get_rate_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
631 {
632  if (entry_number >= decoded->aoc_s_count) {
633  return NULL;
634  }
635 
636  return (const struct ast_aoc_s_entry *) &decoded->aoc_s_entries[entry_number];
637 }
638 
641  unsigned int amount,
642  enum ast_aoc_currency_multiplier multiplier,
643  const char *currency_name,
644  unsigned long time,
645  enum ast_aoc_time_scale time_scale,
646  unsigned long granularity_time,
647  enum ast_aoc_time_scale granularity_time_scale,
648  int step_function)
649 {
650 
651  struct ast_aoc_s_entry entry = { 0, };
652 
653  entry.charged_item = charged_item;
655  entry.rate.duration.amount = amount;
656  entry.rate.duration.multiplier = multiplier;
657  entry.rate.duration.time = time;
658  entry.rate.duration.time_scale = time_scale;
659  entry.rate.duration.granularity_time = granularity_time;
660  entry.rate.duration.granularity_time_scale = granularity_time_scale;
661  entry.rate.duration.charging_type = step_function ? 1 : 0;
662 
663  if (!ast_strlen_zero(currency_name)) {
664  ast_copy_string(entry.rate.duration.currency_name, currency_name, sizeof(entry.rate.duration.currency_name));
665  }
666 
667  return aoc_s_add_entry(decoded, &entry);
668 }
669 
672  unsigned int amount,
673  enum ast_aoc_currency_multiplier multiplier,
674  const char *currency_name)
675 {
676  struct ast_aoc_s_entry entry = { 0, };
677 
678  entry.charged_item = charged_item;
680  entry.rate.flat.amount = amount;
681  entry.rate.flat.multiplier = multiplier;
682 
683  if (!ast_strlen_zero(currency_name)) {
684  ast_copy_string(entry.rate.flat.currency_name, currency_name, sizeof(entry.rate.flat.currency_name));
685  }
686 
687  return aoc_s_add_entry(decoded, &entry);
688 }
689 
690 
693  enum ast_aoc_volume_unit volume_unit,
694  unsigned int amount,
695  enum ast_aoc_currency_multiplier multiplier,
696  const char *currency_name)
697 {
698  struct ast_aoc_s_entry entry = { 0, };
699 
700  entry.charged_item = charged_item;
702  entry.rate.volume.multiplier = multiplier;
703  entry.rate.volume.amount = amount;
704  entry.rate.volume.volume_unit = volume_unit;
705 
706  if (!ast_strlen_zero(currency_name)) {
707  ast_copy_string(entry.rate.volume.currency_name, currency_name, sizeof(entry.rate.volume.currency_name));
708  }
709 
710  return aoc_s_add_entry(decoded, &entry);
711 }
712 
715  unsigned int code)
716 {
717  struct ast_aoc_s_entry entry = { 0, };
718 
719  entry.charged_item = charged_item;
721  entry.rate.special_code = code;
722 
723  return aoc_s_add_entry(decoded, &entry);
724 }
725 
728  int from_beginning)
729 {
730  struct ast_aoc_s_entry entry = { 0, };
731 
732  entry.charged_item = charged_item;
734 
735  return aoc_s_add_entry(decoded, &entry);
736 }
737 
740 {
741  struct ast_aoc_s_entry entry = { 0, };
742 
743  entry.charged_item = charged_item;
745 
746  return aoc_s_add_entry(decoded, &entry);
747 }
748 
750  unsigned int code)
751 {
752  struct ast_aoc_s_entry entry = { 0, };
753 
756  entry.rate.special_code = code;
757 
758  return aoc_s_add_entry(decoded, &entry);
759 }
760 
762 {
763  return decoded->msg_type;
764 }
765 
767 {
768  return decoded->charge_type;
769 }
770 
772 {
773  return decoded->request_flag;
774 }
775 
777  const enum ast_aoc_total_type type)
778 {
779  decoded->total_type = type;
780  return 0;
781 }
782 
784 {
785  return decoded->total_type;
786 }
787 
789  const unsigned int amount,
790  const enum ast_aoc_currency_multiplier multiplier,
791  const char *name)
792 {
793 
794  if (!ast_strlen_zero(name)) {
795  ast_copy_string(decoded->currency_name, name, sizeof(decoded->currency_name));
796  }
797 
798  decoded->currency_amount = amount;
799 
800  if (multiplier && (multiplier < AST_AOC_MULT_NUM_ENTRIES)) {
801  decoded->multiplier = multiplier;
802  } else {
803  decoded->multiplier = AST_AOC_MULT_ONE;
804  }
805 
806  return 0;
807 }
808 
809 unsigned int ast_aoc_get_currency_amount(struct ast_aoc_decoded *decoded)
810 {
811  return decoded->currency_amount;
812 }
813 
815 {
816  return decoded->multiplier;
817 }
818 
820 {
821  switch (decoded->multiplier) {
823  return "0.001";
825  return "0.01";
827  return "0.1";
828  case AST_AOC_MULT_ONE:
829  return "1.0";
830  case AST_AOC_MULT_TEN:
831  return "10.0";
833  return "100.0";
835  return "1000.0";
836  default:
837  return "1.0";
838  }
839 }
840 
841 const char *ast_aoc_get_currency_name(struct ast_aoc_decoded *decoded)
842 {
843  return decoded->currency_name;
844 }
845 
847  const unsigned int amount_is_present,
848  const unsigned int amount,
849  const unsigned int type_is_present,
850  const unsigned int type)
851 {
852  if ((decoded->msg_type == AST_AOC_REQUEST) ||
853  (decoded->unit_count >= ARRAY_LEN(decoded->unit_list))) {
854  return -1;
855  }
856 
857  if (!amount_is_present && !type_is_present) {
858  return -1;
859  }
860 
861  decoded->unit_list[decoded->unit_count].valid_amount = amount_is_present;
862  if (amount_is_present) {
863  decoded->unit_list[decoded->unit_count].amount = amount;
864  } else {
865  decoded->unit_list[decoded->unit_count].amount = 0;
866  }
867 
868  decoded->unit_list[decoded->unit_count].valid_type = type_is_present;
869  if (type_is_present) {
870  decoded->unit_list[decoded->unit_count].type = type;
871  } else {
872  decoded->unit_list[decoded->unit_count].type = 0;
873  }
874  decoded->unit_count++;
875 
876  return 0;
877 }
878 
879 const struct ast_aoc_unit_entry *ast_aoc_get_unit_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
880 {
881  if (entry_number >= decoded->unit_count) {
882  return NULL;
883  }
884 
885  return (const struct ast_aoc_unit_entry *) &decoded->unit_list[entry_number];
886 }
887 
888 unsigned int ast_aoc_get_unit_count(struct ast_aoc_decoded *decoded)
889 {
890  return decoded->unit_count;
891 }
892 
893 int ast_aoc_set_billing_id(struct ast_aoc_decoded *decoded, const enum ast_aoc_billing_id id)
894 {
895  if ((id >= AST_AOC_BILLING_NUM_ENTRIES) || (id < AST_AOC_BILLING_NA)) {
896  return -1;
897  }
898 
899  decoded->billing_id = id;
900 
901  return 0;
902 }
903 
905 {
906  return decoded->billing_id;
907 }
908 
909 int ast_aoc_set_association_id(struct ast_aoc_decoded *decoded, const int id)
910 {
911  if (decoded->msg_type != AST_AOC_E) {
912  return -1;
913  }
914  memset(&decoded->charging_association, 0, sizeof(decoded->charging_association));
916  decoded->charging_association.charge.id = id;
917  return 0;
918 }
919 
921 {
922  return &decoded->charging_association;
923 }
924 
925 int ast_aoc_set_association_number(struct ast_aoc_decoded *decoded, const char *num, uint8_t plan)
926 {
927  if ((decoded->msg_type != AST_AOC_E) || ast_strlen_zero(num)) {
928  return -1;
929  }
930  memset(&decoded->charging_association, 0, sizeof(decoded->charging_association));
932  decoded->charging_association.charge.number.plan = plan;
934 
935  return 0;
936 }
937 
939 {
940  if (decoded->msg_type != AST_AOC_REQUEST) {
941  return -1;
942  }
943  decoded->termination_request = 1;
944 
945  return 0;
946 }
947 
949 {
950  return decoded->termination_request;
951 }
952 
953 /*!
954  * \internal
955  * \brief Convert AST_AOC_VOLUME_UNIT to string.
956  * \since 1.8
957  *
958  * \param value Value to convert to string.
959  *
960  * \return String equivalent.
961  */
963 {
964  const char *str;
965 
966  switch (value) {
967  default:
969  str = "Octet";
970  break;
972  str = "Segment";
973  break;
975  str = "Message";
976  break;
977  }
978  return str;
979 }
980 
981 /*!
982  * \internal
983  * \brief Convert ast_aoc_charged_item to string.
984  * \since 1.8
985  *
986  * \param value Value to convert to string.
987  *
988  * \return String equivalent.
989  */
991 {
992  const char *str;
993 
994  switch (value) {
995  default:
997  str = "NotAvailable";
998  break;
1000  str = "SpecialArrangement";
1001  break;
1003  str = "BasicCommunication";
1004  break;
1006  str = "CallAttempt";
1007  break;
1009  str = "CallSetup";
1010  break;
1012  str = "UserUserInfo";
1013  break;
1015  str = "SupplementaryService";
1016  break;
1017  }
1018  return str;
1019 }
1020 
1021 /*!
1022  * \internal
1023  * \brief Convert ast_aoc_total_type to string.
1024  * \since 1.8
1025  *
1026  * \param value Value to convert to string.
1027  *
1028  * \return String equivalent.
1029  */
1031 {
1032  const char *str;
1033 
1034  switch (value) {
1035  default:
1036  case AST_AOC_SUBTOTAL:
1037  str = "SubTotal";
1038  break;
1039  case AST_AOC_TOTAL:
1040  str = "Total";
1041  break;
1042  }
1043  return str;
1044 }
1045 
1046 /*!
1047  * \internal
1048  * \brief Convert ast_aoc_rate_type to string.
1049  * \since 1.8
1050  *
1051  * \param value Value to convert to string.
1052  *
1053  * \return String equivalent.
1054  */
1056 {
1057  const char *str;
1058 
1059  switch (value) {
1060  default:
1061  case AST_AOC_RATE_TYPE_NA:
1062  str = "NotAvailable";
1063  break;
1065  str = "Free";
1066  break;
1068  str = "FreeFromBeginning";
1069  break;
1071  str = "Duration";
1072  break;
1074  str = "Flat";
1075  break;
1077  str = "Volume";
1078  break;
1080  str = "SpecialCode";
1081  break;
1082  }
1083  return str;
1084 }
1085 
1086 /*!
1087  * \internal
1088  * \brief Convert AST_AOC_TIME_SCALE to string.
1089  * \since 1.8
1090  *
1091  * \param value Value to convert to string.
1092  *
1093  * \return String equivalent.
1094  */
1095 static const char *aoc_scale_str(enum ast_aoc_time_scale value)
1096 {
1097  const char *str;
1098 
1099  switch (value) {
1100  default:
1102  str = "OneHundredthSecond";
1103  break;
1105  str = "OneTenthSecond";
1106  break;
1108  str = "Second";
1109  break;
1111  str = "TenSeconds";
1112  break;
1114  str = "Minute";
1115  break;
1117  str = "Hour";
1118  break;
1120  str = "Day";
1121  break;
1122  }
1123  return str;
1124 }
1125 
1127 {
1128  const char *str;
1129 
1130  switch (value) {
1131  default:
1132  case AST_AOC_CHARGE_NA:
1133  str = "NotAvailable";
1134  break;
1135  case AST_AOC_CHARGE_FREE:
1136  str = "Free";
1137  break;
1139  str = "Currency";
1140  break;
1141  case AST_AOC_CHARGE_UNIT:
1142  str = "Units";
1143  break;
1144  }
1145 
1146  return str;
1147 }
1148 
1150 {
1151  switch (mult) {
1153  return "1/1000";
1155  return "1/100";
1156  case AST_AOC_MULT_ONETENTH:
1157  return "1/10";
1158  case AST_AOC_MULT_ONE:
1159  return "1";
1160  case AST_AOC_MULT_TEN:
1161  return "10";
1162  case AST_AOC_MULT_HUNDRED:
1163  return "100";
1164  case AST_AOC_MULT_THOUSAND:
1165  return "1000";
1167  break;
1168  }
1169  return "1";
1170 }
1171 
1172 static const char *aoc_billingid_str(enum ast_aoc_billing_id billing_id)
1173 {
1174  switch (billing_id) {
1176  return "Normal";
1178  return "Reverse";
1180  return "CreditCard";
1182  return "CallForwardingUnconditional";
1184  return "CallForwardingBusy";
1186  return "CallForwardingNoReply";
1188  return "CallDeflection";
1190  return "CallTransfer";
1191  case AST_AOC_BILLING_NA:
1192  return "NotAvailable";
1194  break;
1195  }
1196  return "NotAvailable";
1197 }
1198 
1200 {
1201  struct ast_aoc_decoded *new_decoded = NULL;
1202  struct ast_aoc_encoded *encoded = NULL;
1203  size_t size;
1204  int res = 0;
1205 
1206  if (!(encoded = ast_aoc_encode(decoded, &size, NULL))) {
1207  return -1;
1208  }
1209 
1210  if (!(new_decoded = ast_aoc_decode(encoded, size, NULL))) {
1211  ast_free(encoded);
1212  return -1;
1213  }
1214 
1215  if (memcmp(new_decoded, decoded, sizeof(struct ast_aoc_decoded))) {
1216  res = -1;
1217  }
1218 
1219  ast_aoc_destroy_decoded(new_decoded);
1220  ast_aoc_destroy_encoded(encoded);
1221  return res;
1222 }
1223 
1224 static char *aoc_cli_debug_enable(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1225 {
1226  switch (cmd) {
1227  case CLI_INIT:
1228  e->command = "aoc set debug";
1229  e->usage =
1230  "Usage: 'aoc set debug on' to enable aoc debug, 'aoc set debug off' to disable debug.\n";
1231  return NULL;
1232  case CLI_GENERATE:
1233  return NULL;
1234  case CLI_HANDLER:
1235  if (a->argc != 4) {
1236  return CLI_SHOWUSAGE;
1237  } else if(ast_true(a->argv[3])) {
1238  ast_cli(a->fd, "aoc debug enabled\n");
1239  aoc_debug_enabled = 1;
1240  } else if (ast_false(a->argv[3])) {
1241  ast_cli(a->fd, "aoc debug disabled\n");
1242  aoc_debug_enabled = 0;
1243  } else {
1244  return CLI_SHOWUSAGE;
1245  }
1246  }
1247 
1248  return CLI_SUCCESS;
1249 }
1250 
1251 /*!
1252  * \internal
1253  * \brief Append the time structure to the event message string.
1254  * \since 1.8
1255  *
1256  * \param msg Event message string being built.
1257  * \param prefix Prefix to add to the amount lines.
1258  * \param name Name of the time structure to convert.
1259  * \param time Data to convert.
1260  * \param scale Data to convert.
1261  *
1262  * \return Nothing
1263  */
1264 static void aoc_time_str(struct ast_str **msg, const char *prefix, const char *name, unsigned long time, enum ast_aoc_time_scale scale)
1265 {
1266  ast_str_append(msg, 0, "%s/%s/Length: %lu\r\n", prefix, name, time);
1267  ast_str_append(msg, 0, "%s/%s/Scale: %s\r\n", prefix, name,
1268  aoc_scale_str(scale));
1269 }
1270 
1271 /*!
1272  * \internal
1273  * \brief Append the amount structure to the event message string.
1274  * \since 1.8
1275  *
1276  * \param msg Event message string being built.
1277  * \param prefix Prefix to add to the amount lines.
1278  * \param amount Data to convert.
1279  * \param multipler to convert
1280  *
1281  * \return Nothing
1282  */
1283 static void aoc_amount_str(struct ast_str **msg, const char *prefix, unsigned int amount, enum ast_aoc_currency_multiplier mult)
1284 {
1285  static const char name[] = "Amount";
1286 
1287  ast_str_append(msg, 0, "%s/%s/Cost: %u\r\n", prefix, name, amount);
1288  ast_str_append(msg, 0, "%s/%s/Multiplier: %s\r\n", prefix, name,
1289  aoc_multiplier_str(mult));
1290 }
1291 
1292 static void aoc_request_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan, struct ast_str **msg)
1293 {
1294  if (chan) {
1295  ast_str_append(msg, 0, "Channel: %s\r\n", chan->name);
1296  ast_str_append(msg, 0, "UniqueID: %s\r\n", chan->uniqueid);
1297  }
1298 
1299  if (decoded->request_flag) {
1300  ast_str_append(msg, 0, "AOCRequest:");
1301  if (decoded->request_flag & AST_AOC_REQUEST_S) {
1302  ast_str_append(msg, 0, "S");
1303  }
1304  if (decoded->request_flag & AST_AOC_REQUEST_D) {
1305  ast_str_append(msg, 0, "D");
1306  }
1307  if (decoded->request_flag & AST_AOC_REQUEST_E) {
1308  ast_str_append(msg, 0, "E");
1309  }
1310  ast_str_append(msg, 0, "\r\n");
1311 
1312  } else {
1313  ast_str_append(msg, 0, "AOCRequest: NONE\r\n");
1314  }
1315 }
1316 
1317 static void aoc_s_event(const struct ast_aoc_decoded *decoded, struct ast_channel *owner, struct ast_str **msg)
1318 {
1319  const char *rate_str;
1320  char prefix[32];
1321  int idx;
1322 
1323  if (owner) {
1324  ast_str_append(msg, 0, "Channel: %s\r\n", owner->name);
1325  ast_str_append(msg, 0, "UniqueID: %s\r\n", owner->uniqueid);
1326  }
1327 
1328  ast_str_append(msg, 0, "NumberRates: %d\r\n", decoded->aoc_s_count);
1329  for (idx = 0; idx < decoded->aoc_s_count; ++idx) {
1330  snprintf(prefix, sizeof(prefix), "Rate(%d)", idx);
1331 
1332  ast_str_append(msg, 0, "%s/Chargeable: %s\r\n", prefix,
1334  if (decoded->aoc_s_entries[idx].charged_item == AST_AOC_CHARGED_ITEM_NA) {
1335  continue;
1336  }
1337  rate_str = aoc_rate_type_str(decoded->aoc_s_entries[idx].rate_type);
1338  ast_str_append(msg, 0, "%s/Type: %s\r\n", prefix, rate_str);
1339  switch (decoded->aoc_s_entries[idx].rate_type) {
1341  strcat(prefix, "/");
1342  strcat(prefix, rate_str);
1343  ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
1344  decoded->aoc_s_entries[idx].rate.duration.currency_name);
1345  aoc_amount_str(msg, prefix,
1346  decoded->aoc_s_entries[idx].rate.duration.amount,
1347  decoded->aoc_s_entries[idx].rate.duration.multiplier);
1348  ast_str_append(msg, 0, "%s/ChargingType: %s\r\n", prefix,
1349  decoded->aoc_s_entries[idx].rate.duration.charging_type ?
1350  "StepFunction" : "ContinuousCharging");
1351  aoc_time_str(msg, prefix, "Time",
1352  decoded->aoc_s_entries[idx].rate.duration.time,
1353  decoded->aoc_s_entries[idx].rate.duration.time_scale);
1354  if (decoded->aoc_s_entries[idx].rate.duration.granularity_time) {
1355  aoc_time_str(msg, prefix, "Granularity",
1358  }
1359  break;
1361  strcat(prefix, "/");
1362  strcat(prefix, rate_str);
1363  ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
1364  decoded->aoc_s_entries[idx].rate.flat.currency_name);
1365  aoc_amount_str(msg, prefix,
1366  decoded->aoc_s_entries[idx].rate.flat.amount,
1367  decoded->aoc_s_entries[idx].rate.flat.multiplier);
1368  break;
1370  strcat(prefix, "/");
1371  strcat(prefix, rate_str);
1372  ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
1373  decoded->aoc_s_entries[idx].rate.volume.currency_name);
1374  aoc_amount_str(msg, prefix,
1375  decoded->aoc_s_entries[idx].rate.volume.amount,
1376  decoded->aoc_s_entries[idx].rate.volume.multiplier);
1377  ast_str_append(msg, 0, "%s/Unit: %s\r\n", prefix,
1379  break;
1381  ast_str_append(msg, 0, "%s/%s: %d\r\n", prefix, rate_str,
1382  decoded->aoc_s_entries[idx].rate.special_code);
1383  break;
1384  default:
1385  break;
1386  }
1387  }
1388 }
1389 
1390 static void aoc_d_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan, struct ast_str **msg)
1391 {
1392  const char *charge_str;
1393  int idx;
1394  char prefix[32];
1395 
1396  if (chan) {
1397  ast_str_append(msg, 0, "Channel: %s\r\n", chan->name);
1398  ast_str_append(msg, 0, "UniqueID: %s\r\n", chan->uniqueid);
1399  }
1400 
1401  charge_str = aoc_charge_type_str(decoded->charge_type);
1402  ast_str_append(msg, 0, "Type: %s\r\n", charge_str);
1403 
1404  switch (decoded->charge_type) {
1406  case AST_AOC_CHARGE_UNIT:
1407  ast_str_append(msg, 0, "BillingID: %s\r\n",
1408  aoc_billingid_str(decoded->billing_id));
1409  ast_str_append(msg, 0, "TypeOfCharging: %s\r\n",
1411  break;
1412  default:
1413  break;
1414  }
1415 
1416  switch (decoded->charge_type) {
1418  ast_str_append(msg, 0, "%s: %s\r\n", charge_str,
1419  decoded->currency_name);
1420  aoc_amount_str(msg, charge_str,
1421  decoded->currency_amount,
1422  decoded->multiplier);
1423  break;
1424  case AST_AOC_CHARGE_UNIT:
1425  ast_str_append(msg, 0, "%s/NumberItems: %d\r\n", charge_str,
1426  decoded->unit_count);
1427  for (idx = 0; idx < decoded->unit_count; ++idx) {
1428  snprintf(prefix, sizeof(prefix), "%s/Item(%d)", charge_str, idx);
1429  if (decoded->unit_list[idx].valid_amount) {
1430  ast_str_append(msg, 0, "%s/NumberOf: %u\r\n", prefix,
1431  decoded->unit_list[idx].amount);
1432  }
1433  if (decoded->unit_list[idx].valid_type) {
1434  ast_str_append(msg, 0, "%s/TypeOf: %u\r\n", prefix,
1435  decoded->unit_list[idx].type);
1436  }
1437  }
1438  break;
1439  default:
1440  break;
1441  }
1442 }
1443 
1444 static void aoc_e_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan, struct ast_str **msg)
1445 {
1446  const char *charge_str;
1447  int idx;
1448  char prefix[32];
1449 
1450  if (chan) {
1451  ast_str_append(msg, 0, "Channel: %s\r\n", chan->name);
1452  ast_str_append(msg, 0, "UniqueID: %s\r\n", chan->uniqueid);
1453  }
1454 
1455  charge_str = "ChargingAssociation";
1456 
1457  switch (decoded->charging_association.charging_type) {
1459  snprintf(prefix, sizeof(prefix), "%s/Number", charge_str);
1460  ast_str_append(msg, 0, "%s: %s\r\n", prefix,
1462  ast_str_append(msg, 0, "%s/Plan: %d\r\n", prefix,
1464  break;
1466  ast_str_append(msg, 0, "%s/ID: %d\r\n", charge_str, decoded->charging_association.charge.id);
1467  break;
1469  default:
1470  break;
1471  }
1472 
1473  charge_str = aoc_charge_type_str(decoded->charge_type);
1474  ast_str_append(msg, 0, "Type: %s\r\n", charge_str);
1475  switch (decoded->charge_type) {
1477  case AST_AOC_CHARGE_UNIT:
1478  ast_str_append(msg, 0, "BillingID: %s\r\n",
1479  aoc_billingid_str(decoded->billing_id));
1480  break;
1481  default:
1482  break;
1483  }
1484  switch (decoded->charge_type) {
1486  ast_str_append(msg, 0, "%s: %s\r\n", charge_str,
1487  decoded->currency_name);
1488  aoc_amount_str(msg, charge_str,
1489  decoded->currency_amount,
1490  decoded->multiplier);
1491  break;
1492  case AST_AOC_CHARGE_UNIT:
1493  ast_str_append(msg, 0, "%s/NumberItems: %d\r\n", charge_str,
1494  decoded->unit_count);
1495  for (idx = 0; idx < decoded->unit_count; ++idx) {
1496  snprintf(prefix, sizeof(prefix), "%s/Item(%d)", charge_str, idx);
1497  if (decoded->unit_list[idx].valid_amount) {
1498  ast_str_append(msg, 0, "%s/NumberOf: %u\r\n", prefix,
1499  decoded->unit_list[idx].amount);
1500  }
1501  if (decoded->unit_list[idx].valid_type) {
1502  ast_str_append(msg, 0, "%s/TypeOf: %u\r\n", prefix,
1503  decoded->unit_list[idx].type);
1504  }
1505  }
1506  break;
1507  default:
1508  break;
1509  }
1510 }
1511 
1512 int ast_aoc_manager_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan)
1513 {
1514  struct ast_str *msg;
1515 
1516  if (!decoded || !(msg = ast_str_create(1024))) {
1517  return -1;
1518  }
1519 
1520  switch (decoded->msg_type) {
1521  case AST_AOC_S:
1522  if (chan) {
1523  aoc_s_event(decoded, chan, &msg);
1524  ast_manager_event(chan, EVENT_FLAG_AOC, "AOC-S", "%s", ast_str_buffer(msg));
1525  }
1526  break;
1527  case AST_AOC_D:
1528  if (chan) {
1529  aoc_d_event(decoded, chan, &msg);
1530  ast_manager_event(chan, EVENT_FLAG_AOC, "AOC-D", "%s", ast_str_buffer(msg));
1531  }
1532  break;
1533  case AST_AOC_E:
1534  {
1535  struct ast_channel *chans[1];
1536  aoc_e_event(decoded, chan, &msg);
1537  chans[0] = chan;
1538  ast_manager_event_multichan(EVENT_FLAG_AOC, "AOC-E", chan ? 1 : 0, chans, "%s", ast_str_buffer(msg));
1539  }
1540  break;
1541  default:
1542  /* events for AST_AOC_REQUEST are not generated here */
1543  break;
1544  }
1545 
1546  ast_free(msg);
1547  return 0;
1548 }
1549 
1550 int ast_aoc_decoded2str(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
1551 {
1552  if (!decoded || !msg) {
1553  return -1;
1554  }
1555 
1556  switch (decoded->msg_type) {
1557  case AST_AOC_S:
1558  ast_str_append(msg, 0, "AOC-S\r\n");
1559  aoc_s_event(decoded, NULL, msg);
1560  break;
1561  case AST_AOC_D:
1562  ast_str_append(msg, 0, "AOC-D\r\n");
1563  aoc_d_event(decoded, NULL, msg);
1564  break;
1565  case AST_AOC_E:
1566  ast_str_append(msg, 0, "AOC-E\r\n");
1567  aoc_e_event(decoded, NULL, msg);
1568  break;
1569  case AST_AOC_REQUEST:
1570  ast_str_append(msg, 0, "AOC-Request\r\n");
1571  aoc_request_event(decoded, NULL, msg);
1572  break;
1573  }
1574 
1575  return 0;
1576 }
1577 
1578 static void aoc_display_decoded_debug(const struct ast_aoc_decoded *decoded, int decoding, struct ast_channel *chan)
1579 {
1580  struct ast_str *msg;
1581 
1582  if (!decoded || !(msg = ast_str_create(1024))) {
1583  return;
1584  }
1585 
1586  if (decoding) {
1587  ast_str_append(&msg, 0, "---- DECODED AOC MSG ----\r\n");
1588  } else {
1589  ast_str_append(&msg, 0, "---- ENCODED AOC MSG ----\r\n");
1590  }
1591  if (chan) {
1592  ast_str_append(&msg, 0, "CHANNEL: %s\r\n", chan->name);
1593  }
1594 
1595  if (ast_aoc_decoded2str(decoded, &msg)) {
1596  ast_free(msg);
1597  return;
1598  }
1599 
1600  ast_verb(1, "%s\r\n", ast_str_buffer(msg));
1601  ast_free(msg);
1602 }
1603 
1604 static struct ast_cli_entry aoc_cli[] = {
1605  AST_CLI_DEFINE(aoc_cli_debug_enable, "enable cli debugging of AOC messages"),
1606 };
1607 
1608 static void aoc_shutdown(void)
1609 {
1610  ast_cli_unregister_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
1611 }
1613 {
1615  return ast_cli_register_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
1616 }
int ast_aoc_decoded2str(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
Convert decoded aoc msg to string representation.
Definition: aoc.c:1550
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:630
uint16_t volume_unit
Definition: aoc.h:134
char valid_amount
Definition: aoc.h:179
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:639
Main Channel structure associated with a channel.
Definition: channel.h:742
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
static void aoc_shutdown(void)
Definition: aoc.c:1608
static void aoc_create_ie_data_charging_rate(const struct ast_aoc_s_entry *entry, struct aoc_ie_charging_rate *ie)
Definition: aoc.c:406
uint16_t datalen
Definition: aoc.c:69
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:1283
struct ast_module::@278 entry
#define AST_AOC_ENCODED_REQUEST_E
Definition: aoc.c:48
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
int ast_aoc_set_termination_request(struct ast_aoc_decoded *decoded)
Mark the AST_AOC_REQUEST message as a termination request.
Definition: aoc.c:938
static int aoc_s_add_entry(struct ast_aoc_decoded *decoded, struct ast_aoc_s_entry *entry)
Definition: aoc.c:612
uint32_t amount
Definition: aoc.c:121
const ast_string_field uniqueid
Definition: channel.h:787
String manipulation functions.
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:846
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:771
int ast_aoc_s_add_special_arrangement(struct ast_aoc_decoded *decoded, unsigned int code)
Add AOC-S special arrangement entry.
Definition: aoc.c:749
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
#define AST_AOC_ENCODED_TYPE_E
Definition: aoc.c:43
static void aoc_e_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan, struct ast_str **msg)
Definition: aoc.c:1444
#define AST_AOC_ENCODED_CHARGE_FREE
Definition: aoc.c:51
enum ast_aoc_currency_multiplier multiplier
Definition: aoc.c:81
static void aoc_request_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan, struct ast_str **msg)
Definition: aoc.c:1292
static struct requests requests
static void aoc_s_event(const struct ast_aoc_decoded *decoded, struct ast_channel *owner, struct ast_str **msg)
Definition: aoc.c:1317
struct ast_aoc_duration_rate duration
Definition: aoc.h:171
descriptor for a cli entry.
Definition: cli.h:165
const int argc
Definition: cli.h:154
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
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:670
static void aoc_parse_ie_charging_rate(struct ast_aoc_decoded *decoded, const struct aoc_ie_charging_rate *ie)
Definition: aoc.c:188
#define AST_AOC_ENCODED_TYPE_D
Definition: aoc.c:42
uint8_t version
Definition: aoc.c:67
Definition: aoc.h:165
uint32_t amount
Definition: aoc.h:132
uint8_t datalen
Definition: aoc.c:116
#define AST_AOC_ENCODED_CHARGE_CURRENCY
Definition: aoc.c:52
unsigned int type
Definition: aoc.h:182
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:783
static const char * aoc_billingid_str(enum ast_aoc_billing_id billing_id)
Definition: aoc.c:1172
struct ast_aoc_charging_association_number number
Definition: aoc.h:197
Definition: cli.h:146
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:176
AOC_IE
AOC Payload Information Elements.
Definition: aoc.c:104
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:713
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:900
#define AST_AOC_ENCODED_REQUEST_S
Definition: aoc.c:46
#define EVENT_FLAG_AOC
Definition: manager.h:87
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
uint16_t charged_item
Definition: aoc.h:166
uint8_t charging_type
Charging interval type.
Definition: aoc.h:122
static const char * aoc_type_of_totaling_str(enum ast_aoc_total_type value)
Definition: aoc.c:1030
uint8_t type
Definition: aoc.c:130
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:691
static const char * aoc_charged_item_str(enum ast_aoc_s_charged_item value)
Definition: aoc.c:990
ast_aoc_currency_multiplier
Defines the currency multiplier for an aoc message.
Definition: aoc.h:34
const char * str
Definition: app_jack.c:144
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:1512
static const char * aoc_volume_unit_str(enum ast_aoc_volume_unit value)
Definition: aoc.c:962
static const char * aoc_multiplier_str(enum ast_aoc_currency_multiplier mult)
Definition: aoc.c:1149
enum ast_aoc_billing_id billing_id
Definition: aoc.c:90
ast_aoc_time_scale
Definition: aoc.h:87
uint32_t amount
Definition: aoc.h:104
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:726
int value
Definition: syslog.c:39
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
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:819
uint8_t valid_amount
Definition: aoc.c:129
uint8_t ie_id
Definition: aoc.c:115
ast_aoc_total_type
Definition: aoc.h:82
#define ast_verb(level,...)
Definition: logger.h:243
Utility functions.
int pos
Definition: aoc.c:383
uint16_t multiplier
Definition: aoc.h:109
#define ast_manager_event(chan, category, event, contents,...)
Definition: manager.h:221
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:925
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:625
enum ast_aoc_total_type total_type
Definition: aoc.c:78
static void aoc_display_decoded_debug(const struct ast_aoc_decoded *decoded, int decoding, struct ast_channel *chan)
Definition: aoc.c:1578
static struct ast_cli_entry aoc_cli[]
Definition: aoc.c:1604
static char * aoc_cli_debug_enable(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: aoc.c:1224
#define AST_AOC_ENCODED_CHARGE_UNIT
Definition: aoc.c:53
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:1055
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:318
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:920
uint16_t special_code
Definition: aoc.h:174
ast_aoc_s_charged_item
Definition: aoc.h:145
const int fd
Definition: cli.h:153
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:738
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
struct ast_aoc_charging_association charging_association
Definition: aoc.c:93
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:519
int unit_count
Definition: aoc.c:86
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
Definition: asterisk.c:998
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:55
uint16_t multiplier
Definition: aoc.h:140
ast_aoc_charge_type
Definition: aoc.h:69
int ast_aoc_cli_init(void)
enable aoc cli options
Definition: aoc.c:1612
int aoc_s_count
Definition: aoc.c:96
uint16_t multiplier
Definition: aoc.h:133
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:809
char currency_name[AOC_CURRENCY_NAME_SIZE]
Definition: aoc.c:83
const char *const * argv
Definition: cli.h:155
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
uint16_t time_scale
Definition: aoc.h:110
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:893
int ast_aoc_test_encode_decode_match(struct ast_aoc_decoded *decoded)
test aoc encode decode routines.
Definition: aoc.c:1199
ast_aoc_type
Definition: aoc.h:62
#define LOG_ERROR
Definition: logger.h:155
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is &quot;true&quot;. This function checks to see whether a string passed to it is an indication of an &quot;true&quot; value. It checks to see if the string is &quot;yes&quot;, &quot;true&quot;, &quot;y&quot;, &quot;t&quot;, &quot;on&quot; or &quot;1&quot;.
Definition: utils.c:1533
static char aoc_debug_enabled
Definition: aoc.c:61
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
struct ast_aoc_volume_rate volume
Definition: aoc.h:173
#define AST_AOC_ENCODED_TYPE_REQUEST
Definition: aoc.c:41
uint8_t flags
Definition: aoc.c:68
#define CLI_SHOWUSAGE
Definition: cli.h:44
uint32_t amount
Definition: aoc.c:127
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:87
const ast_string_field name
Definition: channel.h:787
unsigned int currency_amount
Definition: aoc.c:82
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
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:948
#define AST_AOC_ENCODED_REQUEST_D
Definition: aoc.c:47
uint32_t granularity_time
Definition: aoc.h:107
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:904
static const char name[]
#define ast_free(a)
Definition: astmm.h:97
char * command
Definition: cli.h:180
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:776
uint8_t valid_type
Definition: aoc.c:128
void * ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
free an ast_aoc_encoded object
Definition: aoc.c:182
Prototypes for public functions only of internal interest,.
static const char * aoc_scale_str(enum ast_aoc_time_scale value)
Definition: aoc.c:1095
char currency_name[AOC_CURRENCY_NAME_SIZE]
Definition: aoc.h:114
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:841
char valid_type
Definition: aoc.h:181
ast_aoc_s_rate_type
Definition: aoc.h:155
static const char type[]
Definition: chan_nbs.c:57
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:1264
AOC IE payload header.
Definition: aoc.c:114
const char * usage
Definition: cli.h:171
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:145
union ast_aoc_charging_association::@142 charge
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:766
uint8_t multiplier
Definition: aoc.c:122
#define CLI_SUCCESS
Definition: cli.h:43
unsigned char buf[1024]
Definition: aoc.c:382
uint32_t time
Definition: aoc.h:105
enum ast_aoc_type msg_type
Definition: aoc.c:75
static void aoc_d_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan, struct ast_str **msg)
Definition: aoc.c:1390
Standard Command Line Interface.
struct ast_aoc_charging_association ca
Definition: aoc.c:138
#define ast_calloc(a, b)
Definition: astmm.h:82
#define AST_AOC_ENCODE_VERSION
Definition: aoc.c:58
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
union ast_aoc_s_entry::@141 rate
Charge rate being applied.
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is &quot;false&quot;...
Definition: utils.c:1550
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
#define AOC_CURRENCY_NAME_SIZE
Definition: aoc.h:31
ast_aoc_billing_id
Defines the billing id options for an aoc message.
Definition: aoc.h:49
unsigned char data[0]
Definition: aoc.c:70
#define AST_AOC_ENCODED_CHARGE_NA
Definition: aoc.c:50
struct ast_aoc_s_entry entry
Definition: aoc.c:142
#define ast_manager_event_multichan(category, event, nchans, chans, contents,...)
Definition: manager.h:226
Definition: aoc.h:64
Definition: aoc.h:66
enum ast_aoc_request request_flag
Definition: aoc.c:77
char name[AOC_CURRENCY_NAME_SIZE]
Definition: aoc.c:123
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:909
uint8_t id
Definition: aoc.c:134
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:761
enum queue_result id
Definition: app_queue.c:1090
uint32_t amount
Definition: aoc.h:139
struct ast_aoc_s_entry aoc_s_entries[10]
Definition: aoc.c:97
static void aoc_create_ie_data(struct ast_aoc_decoded *decoded, struct aoc_ie_data *ied)
Definition: aoc.c:452
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:814
Definition: aoc.h:178
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:879
char data[0]
Definition: aoc.c:117
static int aoc_append_ie(struct aoc_ie_data *ied, unsigned short ie_id, const void *data, unsigned short datalen)
Definition: aoc.c:391
uint16_t rate_type
Definition: aoc.h:167
static const char * aoc_charge_type_str(enum ast_aoc_charge_type value)
Definition: aoc.c:1126
#define AST_AOC_ENCODED_TYPE_S
Definition: aoc.c:44
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:888
enum ast_aoc_charge_type charge_type
Definition: aoc.c:76
char termination_request
Definition: aoc.c:100
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:238
uint16_t granularity_time_scale
Definition: aoc.h:111
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
Definition: aoc.h:65
static char prefix[MAX_PREFIX]
Definition: http.c:107
char currency_name[AOC_CURRENCY_NAME_SIZE]
Definition: aoc.h:135
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:788