38 #include "asterisk/stasis_channels.h"
39 #include "asterisk/stasis_message_router.h"
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)
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)
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)
186 #define AST_AOC_ENCODED_CHARGE_SUBTOTAL (1 << 7)
187 #define AST_AOC_ENCODED_CHARGE_TOTAL (0 << 7)
189 #define AST_AOC_ENCODE_VERSION 1
192 static char aoc_debug_enabled = 0;
201 unsigned char data[0];
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;
213 unsigned int currency_amount;
214 char currency_name[AOC_CURRENCY_NAME_SIZE];
231 char termination_request;
239 AOC_IE_CHARGING_ASSOCIATION = 4,
241 AOC_IE_TERMINATION_REQUEST = 6,
249 } __attribute__((packed));
254 char name[AOC_CURRENCY_NAME_SIZE];
255 } __attribute__((packed));
260 uint8_t valid_amount;
262 } __attribute__((packed));
266 } __attribute__((packed));
270 } __attribute__((packed));
274 } __attribute__((packed));
277 const enum ast_aoc_charge_type charge_type,
278 const enum ast_aoc_request
requests)
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)) {
287 ast_log(LOG_WARNING,
"Failed to create ast_aoc_decoded object, invalid input\n");
292 ast_log(LOG_WARNING,
"Failed to create ast_aoc_decoded object \n");
296 decoded->msg_type = msg_type;
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;
323 entry.charged_item = ntohs(ie->entry.charged_item);
324 entry.rate_type = ntohs(ie->entry.rate_type);
326 switch (entry.rate_type) {
327 case AST_AOC_RATE_TYPE_DURATION:
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);
333 entry.
rate.duration.granularity_time_scale = ntohs(ie->entry.
rate.duration.granularity_time_scale);
342 case AST_AOC_RATE_TYPE_FLAT:
343 entry.
rate.flat.multiplier = ntohs(ie->entry.
rate.flat.multiplier);
344 entry.
rate.flat.amount = ntohl(ie->entry.
rate.flat.amount);
351 case AST_AOC_RATE_TYPE_VOLUME:
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);
355 if (!ast_strlen_zero(ie->entry.
rate.volume.currency_name)) {
357 ie->entry.
rate.volume.currency_name,
358 sizeof(entry.
rate.volume.currency_name));
361 case AST_AOC_RATE_TYPE_SPECIAL_CODE:
362 entry.
rate.special_code = ntohs(ie->entry.
rate.special_code);
366 aoc_s_add_entry(decoded, &entry);
369 static int aoc_parse_ie(
struct ast_aoc_decoded *decoded,
unsigned char *data,
unsigned int datalen)
374 while (datalen >= 2) {
377 if (len > datalen -2) {
378 ast_log(LOG_ERROR,
"AOC information element length exceeds the total message size\n");
383 case AOC_IE_CURRENCY:
386 memcpy(&ie, data + 2, len);
387 decoded->currency_amount = ntohl(ie.amount);
388 decoded->multiplier = ie.multiplier;
389 memcpy(decoded->currency_name, ie.name,
sizeof(decoded->currency_name));
391 ast_log(LOG_WARNING,
"Received invalid currency ie\n");
397 memcpy(&ie, data + 2, len);
400 ast_log(LOG_WARNING,
"Received invalid unit ie\n");
406 memcpy(&ie, data + 2, len);
407 decoded->billing_id = ie.id;
409 ast_log(LOG_WARNING,
"Received invalid billing ie\n");
412 case AOC_IE_CHARGING_ASSOCIATION:
414 memcpy(&decoded->charging_association, data + 2,
sizeof(decoded->charging_association));
416 if (decoded->charging_association.
charging_type == AST_AOC_CHARGING_ASSOCIATION_ID) {
417 decoded->charging_association.charge.id = ntohl(decoded->charging_association.charge.id);
420 ast_log(LOG_WARNING,
"Received invalid charging association ie\n");
426 memcpy(&ie, data + 2, len);
427 aoc_parse_ie_charging_rate(decoded, &ie);
429 ast_log(LOG_WARNING,
"Received invalid charging rate ie\n");
432 case AOC_IE_TERMINATION_REQUEST:
434 decoded->termination_request = 1;
436 ast_log(LOG_WARNING,
"Received invalid termination request ie\n");
440 ast_log(LOG_WARNING,
"Unknown AOC Information Element, ignoring.\n");
443 datalen -= (len + 2);
454 if ((size - (
sizeof(
struct ast_aoc_encoded)) != ntohs(encoded->datalen))) {
455 ast_log(LOG_WARNING,
"Corrupted aoc encoded object, can not decode\n");
460 ast_log(LOG_WARNING,
"Failed to create ast_aoc_decoded object \n");
466 if ((encoded->flags & AST_AOC_ENCODED_TYPE_S) == AST_AOC_ENCODED_TYPE_S) {
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;
473 decoded->msg_type = AST_AOC_REQUEST;
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;
480 if (encoded->flags & AST_AOC_ENCODED_REQUEST_D) {
481 decoded->request_flag |= AST_AOC_REQUEST_D;
483 if (encoded->flags & AST_AOC_ENCODED_REQUEST_E) {
484 decoded->request_flag |= AST_AOC_REQUEST_E;
486 }
else if ((decoded->msg_type == AST_AOC_D) || (decoded->msg_type == AST_AOC_E)) {
487 if ((encoded->flags & AST_AOC_ENCODED_CHARGE_UNIT) == AST_AOC_ENCODED_CHARGE_UNIT) {
488 decoded->charge_type = AST_AOC_CHARGE_UNIT;
489 }
else if ((encoded->flags & AST_AOC_ENCODED_CHARGE_CURRENCY) == AST_AOC_ENCODED_CHARGE_CURRENCY) {
490 decoded->charge_type = AST_AOC_CHARGE_CURRENCY;
491 }
else if ((encoded->flags & AST_AOC_ENCODED_CHARGE_FREE) == AST_AOC_ENCODED_CHARGE_FREE) {
492 decoded->charge_type = AST_AOC_CHARGE_FREE;
494 decoded->charge_type = AST_AOC_CHARGE_NA;
497 if (encoded->flags & AST_AOC_ENCODED_CHARGE_SUBTOTAL) {
498 decoded->total_type = AST_AOC_SUBTOTAL;
503 aoc_parse_ie(decoded, encoded->data, ntohs(encoded->datalen));
505 if (aoc_debug_enabled) {
506 aoc_display_decoded_debug(decoded, 1, chan);
513 unsigned char buf[1024];
522 static int aoc_append_ie(
struct aoc_ie_data *ied,
unsigned short ie_id,
const void *data,
unsigned short datalen)
524 if (datalen > ((
int)
sizeof(ied->buf) - ied->pos)) {
525 ast_log(LOG_WARNING,
"Failure to append AOC information element, out of space \n");
528 ied->buf[ied->pos++] = ie_id;
529 ied->buf[ied->pos++] = datalen;
531 memcpy(ied->buf + ied->pos, data, datalen);
539 ie->entry.charged_item = htons(entry->charged_item);
540 ie->entry.rate_type = htons(entry->rate_type);
542 switch (entry->rate_type) {
543 case AST_AOC_RATE_TYPE_DURATION:
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);
549 ie->entry.
rate.duration.granularity_time_scale = htons(entry->
rate.duration.granularity_time_scale);
558 case AST_AOC_RATE_TYPE_FLAT:
559 ie->entry.
rate.flat.multiplier = htons(entry->
rate.flat.multiplier);
560 ie->entry.
rate.flat.amount = htonl(entry->
rate.flat.amount);
567 case AST_AOC_RATE_TYPE_VOLUME:
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));
577 case AST_AOC_RATE_TYPE_SPECIAL_CODE:
578 ie->entry.
rate.special_code = htons(entry->
rate.special_code);
587 if (decoded->currency_amount) {
589 .amount = htonl(decoded->currency_amount),
590 .multiplier = decoded->multiplier,
594 if (!ast_strlen_zero(decoded->currency_name)) {
598 aoc_append_ie(ied, AOC_IE_CURRENCY, (
const void *) &ie,
sizeof(ie));
601 if (decoded->unit_count) {
605 for (i = 0; i < decoded->unit_count; i++) {
606 ie.valid_amount = decoded->unit_list[i].valid_amount;
607 ie.amount = htonl(decoded->unit_list[i].amount);
608 ie.valid_type = decoded->unit_list[i].valid_type;
609 ie.type = decoded->unit_list[i].type;
610 aoc_append_ie(ied, AOC_IE_UNIT, (
const void *) &ie,
sizeof(ie));
614 if (decoded->billing_id) {
616 ie.id = decoded->billing_id;
617 aoc_append_ie(ied, AOC_IE_BILLING, (
const void *) &ie,
sizeof(ie));
620 if (decoded->charging_association.
charging_type != AST_AOC_CHARGING_ASSOCIATION_NA) {
622 memset(&ie, 0,
sizeof(ie));
623 ie.ca.charging_type = decoded->charging_association.
charging_type;
624 if (decoded->charging_association.
charging_type == AST_AOC_CHARGING_ASSOCIATION_NUMBER) {
625 ie.ca.charge.number.plan = decoded->charging_association.charge.number.plan;
627 decoded->charging_association.charge.number.number,
628 sizeof(ie.ca.charge.number.number));
629 }
else if (decoded->charging_association.
charging_type == AST_AOC_CHARGING_ASSOCIATION_ID) {
630 ie.ca.charge.id = htonl(decoded->charging_association.charge.id);
632 aoc_append_ie(ied, AOC_IE_CHARGING_ASSOCIATION, (
const void *) &ie,
sizeof(ie));
635 if (decoded->aoc_s_count) {
638 for (i = 0; i < decoded->aoc_s_count; i++) {
639 memset(&ie, 0,
sizeof(ie));
640 aoc_create_ie_data_charging_rate(&decoded->aoc_s_entries[i], &ie);
641 aoc_append_ie(ied, AOC_IE_RATE, (
const void *) &ie,
sizeof(ie));
645 if (decoded->termination_request) {
646 aoc_append_ie(ied, AOC_IE_TERMINATION_REQUEST, NULL, 0);
656 if (!decoded || !out_size) {
665 aoc_create_ie_data(decoded, &ied);
670 ast_log(LOG_WARNING,
"Failed to create ast_aoc_encoded object during decode routine. \n");
677 memcpy(encoded->data, ied.buf, ied.pos);
678 encoded->datalen = htons(ied.pos);
682 switch (decoded->msg_type) {
684 encoded->flags = AST_AOC_ENCODED_TYPE_S;
687 encoded->flags = AST_AOC_ENCODED_TYPE_D;
690 encoded->flags = AST_AOC_ENCODED_TYPE_E;
692 case AST_AOC_REQUEST:
693 encoded->flags = AST_AOC_ENCODED_TYPE_REQUEST;
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;
703 if (decoded->request_flag & AST_AOC_REQUEST_D) {
704 encoded->flags |= AST_AOC_ENCODED_REQUEST_D;
706 if (decoded->request_flag & AST_AOC_REQUEST_E) {
707 encoded->flags |= AST_AOC_ENCODED_REQUEST_E;
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:
712 encoded->flags |= AST_AOC_ENCODED_CHARGE_UNIT;
714 case AST_AOC_CHARGE_CURRENCY:
715 encoded->flags |= AST_AOC_ENCODED_CHARGE_CURRENCY;
717 case AST_AOC_CHARGE_FREE:
718 encoded->flags |= AST_AOC_ENCODED_CHARGE_FREE;
719 case AST_AOC_CHARGE_NA:
721 encoded->flags |= AST_AOC_ENCODED_CHARGE_NA;
725 if (decoded->total_type == AST_AOC_SUBTOTAL) {
726 encoded->flags |= AST_AOC_ENCODED_CHARGE_SUBTOTAL;
731 encoded->version = AST_AOC_ENCODE_VERSION;
736 if (aoc_debug_enabled) {
737 aoc_display_decoded_debug(decoded, 0, chan);
745 if (decoded->aoc_s_count >= ARRAY_LEN(decoded->aoc_s_entries)) {
749 decoded->aoc_s_entries[decoded->aoc_s_count] = *entry;
750 decoded->aoc_s_count++;
758 return decoded->aoc_s_count;
763 if (entry_number >= decoded->aoc_s_count) {
767 return (
const struct ast_aoc_s_entry *) &decoded->aoc_s_entries[entry_number];
771 enum ast_aoc_s_charged_item charged_item,
774 const char *currency_name,
776 enum ast_aoc_time_scale time_scale,
777 unsigned long granularity_time,
778 enum ast_aoc_time_scale granularity_time_scale,
784 entry.charged_item = charged_item;
785 entry.rate_type = AST_AOC_RATE_TYPE_DURATION;
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;
791 entry.
rate.duration.granularity_time_scale = granularity_time_scale;
794 if (!ast_strlen_zero(currency_name)) {
798 return aoc_s_add_entry(decoded, &entry);
802 enum ast_aoc_s_charged_item charged_item,
805 const char *currency_name)
809 entry.charged_item = charged_item;
810 entry.rate_type = AST_AOC_RATE_TYPE_FLAT;
811 entry.
rate.flat.amount = amount;
812 entry.
rate.flat.multiplier = multiplier;
814 if (!ast_strlen_zero(currency_name)) {
818 return aoc_s_add_entry(decoded, &entry);
823 enum ast_aoc_s_charged_item charged_item,
824 enum ast_aoc_volume_unit volume_unit,
827 const char *currency_name)
831 entry.charged_item = charged_item;
832 entry.rate_type = AST_AOC_RATE_TYPE_VOLUME;
833 entry.
rate.volume.multiplier = multiplier;
834 entry.
rate.volume.amount = amount;
835 entry.
rate.volume.volume_unit = volume_unit;
837 if (!ast_strlen_zero(currency_name)) {
841 return aoc_s_add_entry(decoded, &entry);
845 enum ast_aoc_s_charged_item charged_item,
850 entry.charged_item = charged_item;
851 entry.rate_type = AST_AOC_RATE_TYPE_SPECIAL_CODE;
852 entry.
rate.special_code = code;
854 return aoc_s_add_entry(decoded, &entry);
858 enum ast_aoc_s_charged_item charged_item,
863 entry.charged_item = charged_item;
864 entry.rate_type = from_beginning ? AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING : AST_AOC_RATE_TYPE_FREE;
866 return aoc_s_add_entry(decoded, &entry);
870 enum ast_aoc_s_charged_item charged_item)
874 entry.charged_item = charged_item;
875 entry.rate_type = AST_AOC_RATE_TYPE_NA;
877 return aoc_s_add_entry(decoded, &entry);
885 entry.charged_item = AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
886 entry.rate_type = AST_AOC_RATE_TYPE_SPECIAL_CODE;
887 entry.
rate.special_code = code;
889 return aoc_s_add_entry(decoded, &entry);
894 return decoded->msg_type;
899 return decoded->charge_type;
904 return decoded->request_flag;
908 const enum ast_aoc_total_type type)
910 decoded->total_type = type;
916 return decoded->total_type;
920 const unsigned int amount,
925 if (!ast_strlen_zero(name)) {
926 ast_copy_string(decoded->currency_name, name,
sizeof(decoded->currency_name));
929 decoded->currency_amount = amount;
931 if (multiplier && (multiplier < AST_AOC_MULT_NUM_ENTRIES)) {
932 decoded->multiplier = multiplier;
934 decoded->multiplier = AST_AOC_MULT_ONE;
942 return decoded->currency_amount;
947 return decoded->multiplier;
952 switch (decoded->multiplier) {
953 case AST_AOC_MULT_ONETHOUSANDTH:
955 case AST_AOC_MULT_ONEHUNDREDTH:
957 case AST_AOC_MULT_ONETENTH:
959 case AST_AOC_MULT_ONE:
961 case AST_AOC_MULT_TEN:
963 case AST_AOC_MULT_HUNDRED:
965 case AST_AOC_MULT_THOUSAND:
974 return decoded->currency_name;
978 const unsigned int amount_is_present,
979 const unsigned int amount,
980 const unsigned int type_is_present,
981 const unsigned int type)
983 if ((decoded->msg_type == AST_AOC_REQUEST) ||
984 (decoded->unit_count >= ARRAY_LEN(decoded->unit_list))) {
988 if (!amount_is_present && !type_is_present) {
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;
996 decoded->unit_list[decoded->unit_count].amount = 0;
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;
1003 decoded->unit_list[decoded->unit_count].type = 0;
1005 decoded->unit_count++;
1012 if (entry_number >= decoded->unit_count) {
1021 return decoded->unit_count;
1026 if ((
id >= AST_AOC_BILLING_NUM_ENTRIES) || (
id < AST_AOC_BILLING_NA)) {
1030 decoded->billing_id = id;
1037 return decoded->billing_id;
1042 if (decoded->msg_type != AST_AOC_E) {
1045 memset(&decoded->charging_association, 0,
sizeof(decoded->charging_association));
1046 decoded->charging_association.
charging_type = AST_AOC_CHARGING_ASSOCIATION_ID;
1047 decoded->charging_association.charge.id = id;
1053 return &decoded->charging_association;
1058 if ((decoded->msg_type != AST_AOC_E) || ast_strlen_zero(num)) {
1061 memset(&decoded->charging_association, 0,
sizeof(decoded->charging_association));
1062 decoded->charging_association.
charging_type = AST_AOC_CHARGING_ASSOCIATION_NUMBER;
1063 decoded->charging_association.charge.number.plan = plan;
1064 ast_copy_string(decoded->charging_association.charge.number.number, num,
sizeof(decoded->charging_association.charge.number.number));
1071 if (decoded->msg_type != AST_AOC_REQUEST) {
1074 decoded->termination_request = 1;
1081 return decoded->termination_request;
1093 static const char *aoc_volume_unit_str(
enum ast_aoc_volume_unit value)
1099 case AST_AOC_VOLUME_UNIT_OCTET:
1102 case AST_AOC_VOLUME_UNIT_SEGMENT:
1105 case AST_AOC_VOLUME_UNIT_MESSAGE:
1121 static const char *aoc_charged_item_str(
enum ast_aoc_s_charged_item value)
1127 case AST_AOC_CHARGED_ITEM_NA:
1128 str =
"NotAvailable";
1130 case AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT:
1131 str =
"SpecialArrangement";
1133 case AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION:
1134 str =
"BasicCommunication";
1136 case AST_AOC_CHARGED_ITEM_CALL_ATTEMPT:
1137 str =
"CallAttempt";
1139 case AST_AOC_CHARGED_ITEM_CALL_SETUP:
1142 case AST_AOC_CHARGED_ITEM_USER_USER_INFO:
1143 str =
"UserUserInfo";
1145 case AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE:
1146 str =
"SupplementaryService";
1161 static const char *aoc_type_of_totaling_str(
enum ast_aoc_total_type value)
1167 case AST_AOC_SUBTOTAL:
1186 static const char *aoc_rate_type_str(
enum ast_aoc_s_rate_type value)
1192 case AST_AOC_RATE_TYPE_NA:
1193 str =
"NotAvailable";
1195 case AST_AOC_RATE_TYPE_FREE:
1198 case AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING:
1199 str =
"FreeFromBeginning";
1201 case AST_AOC_RATE_TYPE_DURATION:
1204 case AST_AOC_RATE_TYPE_FLAT:
1207 case AST_AOC_RATE_TYPE_VOLUME:
1210 case AST_AOC_RATE_TYPE_SPECIAL_CODE:
1211 str =
"SpecialCode";
1226 static const char *aoc_scale_str(
enum ast_aoc_time_scale value)
1232 case AST_AOC_TIME_SCALE_HUNDREDTH_SECOND:
1233 str =
"OneHundredthSecond";
1235 case AST_AOC_TIME_SCALE_TENTH_SECOND:
1236 str =
"OneTenthSecond";
1238 case AST_AOC_TIME_SCALE_SECOND:
1241 case AST_AOC_TIME_SCALE_TEN_SECOND:
1244 case AST_AOC_TIME_SCALE_MINUTE:
1247 case AST_AOC_TIME_SCALE_HOUR:
1250 case AST_AOC_TIME_SCALE_DAY:
1257 static const char *aoc_charge_type_str(
enum ast_aoc_charge_type value)
1263 case AST_AOC_CHARGE_NA:
1264 str =
"NotAvailable";
1266 case AST_AOC_CHARGE_FREE:
1269 case AST_AOC_CHARGE_CURRENCY:
1272 case AST_AOC_CHARGE_UNIT:
1283 case AST_AOC_MULT_ONETHOUSANDTH:
1285 case AST_AOC_MULT_ONEHUNDREDTH:
1287 case AST_AOC_MULT_ONETENTH:
1289 case AST_AOC_MULT_ONE:
1291 case AST_AOC_MULT_TEN:
1293 case AST_AOC_MULT_HUNDRED:
1295 case AST_AOC_MULT_THOUSAND:
1297 case AST_AOC_MULT_NUM_ENTRIES:
1305 switch (billing_id) {
1306 case AST_AOC_BILLING_NORMAL:
1308 case AST_AOC_BILLING_REVERSE_CHARGE:
1310 case AST_AOC_BILLING_CREDIT_CARD:
1311 return "CreditCard";
1312 case AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL:
1313 return "CallForwardingUnconditional";
1314 case AST_AOC_BILLING_CALL_FWD_BUSY:
1315 return "CallForwardingBusy";
1316 case AST_AOC_BILLING_CALL_FWD_NO_REPLY:
1317 return "CallForwardingNoReply";
1318 case AST_AOC_BILLING_CALL_DEFLECTION:
1319 return "CallDeflection";
1320 case AST_AOC_BILLING_CALL_TRANSFER:
1321 return "CallTransfer";
1322 case AST_AOC_BILLING_NA:
1323 return "NotAvailable";
1324 case AST_AOC_BILLING_NUM_ENTRIES:
1327 return "NotAvailable";
1361 "Usage: 'aoc set debug on' to enable aoc debug, 'aoc set debug off' to disable debug.\n";
1367 return CLI_SHOWUSAGE;
1369 ast_cli(a->fd,
"aoc debug enabled\n");
1370 aoc_debug_enabled = 1;
1372 ast_cli(a->fd,
"aoc debug disabled\n");
1373 aoc_debug_enabled = 0;
1375 return CLI_SHOWUSAGE;
1393 static void aoc_time_str(
struct ast_str **msg,
const char *prefix,
const char *name,
unsigned long time,
enum ast_aoc_time_scale scale)
1395 ast_str_append(msg, 0,
"%s/%s/Length: %lu\r\n", prefix, name, time);
1397 aoc_scale_str(scale));
1412 static const char name[] =
"Amount";
1414 ast_str_append(msg, 0,
"%s/%s/Cost: %u\r\n", prefix, name, amount);
1416 aoc_multiplier_str(mult));
1421 if (decoded->request_flag) {
1423 if (decoded->request_flag & AST_AOC_REQUEST_S) {
1426 if (decoded->request_flag & AST_AOC_REQUEST_D) {
1429 if (decoded->request_flag & AST_AOC_REQUEST_E) {
1441 const char *rate_str;
1445 ast_str_append(msg, 0,
"NumberRates: %d\r\n", decoded->aoc_s_count);
1446 for (idx = 0; idx < decoded->aoc_s_count; ++idx) {
1447 snprintf(prefix,
sizeof(prefix),
"Rate(%d)", idx);
1450 aoc_charged_item_str(decoded->aoc_s_entries[idx].charged_item));
1451 if (decoded->aoc_s_entries[idx].charged_item == AST_AOC_CHARGED_ITEM_NA) {
1454 rate_str = aoc_rate_type_str(decoded->aoc_s_entries[idx].rate_type);
1456 switch (decoded->aoc_s_entries[idx].rate_type) {
1457 case AST_AOC_RATE_TYPE_DURATION:
1458 strcat(prefix,
"/");
1459 strcat(prefix, rate_str);
1462 aoc_amount_str(msg, prefix,
1463 decoded->aoc_s_entries[idx].
rate.duration.amount,
1464 decoded->aoc_s_entries[idx].
rate.duration.multiplier);
1467 "StepFunction" :
"ContinuousCharging");
1468 aoc_time_str(msg, prefix,
"Time",
1469 decoded->aoc_s_entries[idx].
rate.duration.time,
1470 decoded->aoc_s_entries[idx].
rate.duration.time_scale);
1472 aoc_time_str(msg, prefix,
"Granularity",
1474 decoded->aoc_s_entries[idx].
rate.duration.granularity_time_scale);
1477 case AST_AOC_RATE_TYPE_FLAT:
1478 strcat(prefix,
"/");
1479 strcat(prefix, rate_str);
1482 aoc_amount_str(msg, prefix,
1483 decoded->aoc_s_entries[idx].
rate.flat.amount,
1484 decoded->aoc_s_entries[idx].
rate.flat.multiplier);
1486 case AST_AOC_RATE_TYPE_VOLUME:
1487 strcat(prefix,
"/");
1488 strcat(prefix, rate_str);
1490 decoded->aoc_s_entries[idx].
rate.volume.currency_name);
1491 aoc_amount_str(msg, prefix,
1492 decoded->aoc_s_entries[idx].
rate.volume.amount,
1493 decoded->aoc_s_entries[idx].
rate.volume.multiplier);
1495 aoc_volume_unit_str(decoded->aoc_s_entries[idx].
rate.volume.volume_unit));
1497 case AST_AOC_RATE_TYPE_SPECIAL_CODE:
1499 decoded->aoc_s_entries[idx].
rate.special_code);
1509 const char *charge_str;
1513 charge_str = aoc_charge_type_str(decoded->charge_type);
1516 switch (decoded->charge_type) {
1517 case AST_AOC_CHARGE_CURRENCY:
1518 case AST_AOC_CHARGE_UNIT:
1520 aoc_billingid_str(decoded->billing_id));
1522 aoc_type_of_totaling_str(decoded->total_type));
1528 switch (decoded->charge_type) {
1529 case AST_AOC_CHARGE_CURRENCY:
1531 decoded->currency_name);
1532 aoc_amount_str(msg, charge_str,
1533 decoded->currency_amount,
1534 decoded->multiplier);
1536 case AST_AOC_CHARGE_UNIT:
1538 decoded->unit_count);
1539 for (idx = 0; idx < decoded->unit_count; ++idx) {
1540 snprintf(prefix,
sizeof(prefix),
"%s/Item(%d)", charge_str, idx);
1541 if (decoded->unit_list[idx].valid_amount) {
1543 decoded->unit_list[idx].amount);
1545 if (decoded->unit_list[idx].valid_type) {
1547 decoded->unit_list[idx].type);
1558 const char *charge_str;
1562 charge_str =
"ChargingAssociation";
1565 case AST_AOC_CHARGING_ASSOCIATION_NUMBER:
1566 snprintf(prefix,
sizeof(prefix),
"%s/Number", charge_str);
1568 decoded->charging_association.charge.number.number);
1570 decoded->charging_association.charge.number.plan);
1572 case AST_AOC_CHARGING_ASSOCIATION_ID:
1573 ast_str_append(msg, 0,
"%s/ID: %d\r\n", charge_str, decoded->charging_association.charge.id);
1575 case AST_AOC_CHARGING_ASSOCIATION_NA:
1580 charge_str = aoc_charge_type_str(decoded->charge_type);
1582 switch (decoded->charge_type) {
1583 case AST_AOC_CHARGE_CURRENCY:
1584 case AST_AOC_CHARGE_UNIT:
1586 aoc_billingid_str(decoded->billing_id));
1591 switch (decoded->charge_type) {
1592 case AST_AOC_CHARGE_CURRENCY:
1594 decoded->currency_name);
1595 aoc_amount_str(msg, charge_str,
1596 decoded->currency_amount,
1597 decoded->multiplier);
1599 case AST_AOC_CHARGE_UNIT:
1601 decoded->unit_count);
1602 for (idx = 0; idx < decoded->unit_count; ++idx) {
1603 snprintf(prefix,
sizeof(prefix),
"%s/Item(%d)", charge_str, idx);
1604 if (decoded->unit_list[idx].valid_amount) {
1606 decoded->unit_list[idx].amount);
1608 if (decoded->unit_list[idx].valid_type) {
1610 decoded->unit_list[idx].type);
1628 for (i = 0; i < decoded->unit_count; ++i) {
1631 if (decoded->unit_list[i].valid_amount) {
1634 "%u", decoded->unit_list[i].amount));
1637 if (decoded->unit_list[i].valid_type) {
1640 "%u", decoded->unit_list[i].type));
1651 static struct ast_json *currency_to_json(
const char *name,
int cost,
1657 "Multiplier", aoc_multiplier_str(mult));
1663 const char *obj_type;
1665 if (decoded->charge_type != AST_AOC_CHARGE_CURRENCY &&
1666 decoded->charge_type != AST_AOC_CHARGE_UNIT) {
1668 "Type", aoc_charge_type_str(decoded->charge_type));
1671 if (decoded->charge_type == AST_AOC_CHARGE_CURRENCY) {
1672 obj_type =
"Currency";
1673 obj = currency_to_json(decoded->currency_name, decoded->currency_amount,
1674 decoded->multiplier);
1677 obj = units_to_json(decoded);
1681 "Type", aoc_charge_type_str(decoded->charge_type),
1682 "BillingID", aoc_billingid_str(decoded->billing_id),
1683 "TotalType", aoc_type_of_totaling_str(decoded->total_type),
1690 case AST_AOC_CHARGING_ASSOCIATION_NUMBER:
1693 "Plan", decoded->charging_association.charge.number.plan);
1694 case AST_AOC_CHARGING_ASSOCIATION_ID:
1695 return ast_json_pack(
"{s:i}",
"ID", decoded->charging_association.charge.id);
1696 case AST_AOC_CHARGING_ASSOCIATION_NA:
1711 for (i = 0; i < decoded->aoc_s_count; ++i) {
1715 const char *charge_item = aoc_charged_item_str(
1716 decoded->aoc_s_entries[i].charged_item);
1718 if (decoded->aoc_s_entries[i].charged_item == AST_AOC_CHARGED_ITEM_NA) {
1726 switch (decoded->aoc_s_entries[i].rate_type) {
1727 case AST_AOC_RATE_TYPE_DURATION:
1730 struct ast_json *granularity = NULL;
1732 currency = currency_to_json(
1734 decoded->aoc_s_entries[i].
rate.duration.amount,
1735 decoded->aoc_s_entries[i].
rate.duration.multiplier);
1739 "Scale", decoded->aoc_s_entries[i].
rate.duration.time_scale);
1744 "Scale", decoded->aoc_s_entries[i].
rate.duration.granularity_time_scale);
1748 "Currency", currency,
1750 ?
"StepFunction" :
"ContinuousCharging",
1756 case AST_AOC_RATE_TYPE_FLAT:
1757 currency = currency_to_json(
1759 decoded->aoc_s_entries[i].
rate.flat.amount,
1760 decoded->aoc_s_entries[i].
rate.flat.multiplier);
1764 case AST_AOC_RATE_TYPE_VOLUME:
1765 currency = currency_to_json(
1766 decoded->aoc_s_entries[i].
rate.volume.currency_name,
1767 decoded->aoc_s_entries[i].
rate.volume.amount,
1768 decoded->aoc_s_entries[i].
rate.volume.multiplier);
1771 "Unit", aoc_volume_unit_str(
1772 decoded->aoc_s_entries[i].
rate.volume.volume_unit),
1773 "Currency", currency);
1775 case AST_AOC_RATE_TYPE_SPECIAL_CODE:
1777 "SpecialCode", decoded->aoc_s_entries[i].
rate.special_code);
1784 "Chargeable", charge_item,
1785 aoc_rate_type_str(decoded->aoc_s_entries[i].rate_type), type);
1795 return ast_json_pack(
"{s:o}",
"Charge", charge_to_json(decoded));
1801 "ChargingAssociation", association_to_json(decoded),
1802 "Charge", charge_to_json(decoded));
1812 static void aoc_event_blob_dtor(
void *obj)
1839 aoc_event = ao2_alloc_options(
sizeof(*aoc_event), aoc_event_blob_dtor,
1846 ast_channel_lock(chan);
1848 ast_channel_unlock(chan);
1866 const char *event_name)
1869 struct ast_str *channel = NULL;
1893 return aoc_to_ami(message,
"AOC-S");
1898 return aoc_to_ami(message,
"AOC-D");
1903 return aoc_to_ami(message,
"AOC-E");
1912 .to_ami = aoc_s_to_ami);
1916 .to_ami = aoc_d_to_ami);
1920 .to_ami = aoc_e_to_ami);
1931 switch (decoded->msg_type) {
1933 blob = s_to_json(decoded);
1934 msg_type = aoc_s_type();
1937 blob = d_to_json(decoded);
1938 msg_type = aoc_d_type();
1941 blob = e_to_json(decoded);
1942 msg_type = aoc_e_type();
1949 aoc_publish_blob(chan, msg_type, blob);
1956 if (!decoded || !msg) {
1960 switch (decoded->msg_type) {
1963 aoc_s_event(decoded, msg);
1967 aoc_d_event(decoded, msg);
1971 aoc_e_event(decoded, msg);
1973 case AST_AOC_REQUEST:
1975 aoc_request_event(decoded, msg);
1996 ast_str_append(&msg, 0,
"CHANNEL: %s\r\n", ast_channel_name(chan));
2009 AST_CLI_DEFINE(aoc_cli_debug_enable,
"enable cli debugging of AOC messages"),
2012 static void aoc_shutdown(
void)
Struct containing info for an AMI event to send out.
Main Channel structure associated with a channel.
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Asterisk main include file. File version handling, generic pbx functions.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
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
String manipulation functions.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
void * ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
free an ast_aoc_encoded object
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.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
union ast_aoc_s_entry::@180 rate
Charge rate being applied.
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
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
descriptor for a cli entry.
int ast_aoc_test_encode_decode_match(struct ast_aoc_decoded *decoded)
test aoc encode decode routines.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
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
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Structure representing a snapshot of channel state.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
int ast_aoc_decoded2str(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
Convert decoded aoc msg to string representation.
struct ast_json * ast_json_stringf(const char *format,...)
Create a JSON string, printf style.
AOC_IE
AOC Payload Information Elements.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
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
uint8_t charging_type
Charging interval type.
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.
ast_aoc_currency_multiplier
Defines the currency multiplier for an aoc message.
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
int ast_json_is_null(const struct ast_json *value)
Check if value is JSON null.
int ast_aoc_set_termination_request(struct ast_aoc_decoded *decoded)
Mark the AST_AOC_REQUEST message as a termination request.
const char * ast_aoc_get_currency_name(struct ast_aoc_decoded *decoded)
get the currency name for AOC-D and AOC-E messages
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.
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.
int ast_aoc_s_add_special_arrangement(struct ast_aoc_decoded *decoded, unsigned int code)
Add AOC-S special arrangement entry.
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
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.
struct ast_json * ast_json_null(void)
Get the JSON null value.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
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.
struct ast_channel_snapshot * snapshot
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.
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
Generic Advice of Charge encode and decode routines.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
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
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
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.
char currency_name[AOC_CURRENCY_NAME_SIZE]
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
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
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define STASIS_MESSAGE_TYPE_DEFN(name,...)
Boiler-plate messaging macro for defining public message types.
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".
Support for dynamic strings.
int ast_aoc_set_association_number(struct ast_aoc_decoded *decoded, const char *num, uint8_t plan)
set the charging association number for an AOC-E message
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
struct ast_aoc_decoded * ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan)
decodes an encoded aoc payload.
uint32_t granularity_time
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
#define ast_calloc(num, len)
A wrapper for calloc()
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.
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
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
Prototypes for public functions only of internal interest,.
char currency_name[AOC_CURRENCY_NAME_SIZE]
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
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
int ast_aoc_cli_init(void)
enable aoc cli options
unsigned int ast_aoc_get_currency_amount(struct ast_aoc_decoded *decoded)
get the currency amount for AOC-D and AOC-E messages
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.
struct ast_json * ast_json_object_create(void)
Create a new JSON object.
unsigned int ast_aoc_s_get_count(struct ast_aoc_decoded *decoded)
get the number rates associated with an AOC-S message
Standard Command Line Interface.
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
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
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.
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
ast_aoc_billing_id
Defines the billing id options for an aoc message.
Abstract JSON element (object, array, string, int, ...).
int ast_aoc_get_termination_request(struct ast_aoc_decoded *decoded)
get whether or not the AST_AOC_REQUEST message as a termination request.
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.
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.
#define AST_JSON_UTF8_VALIDATE(str)
Check str for UTF-8 and replace with an empty string if fails the check.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
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