00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "asterisk.h"
00031 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413586 $");
00032
00033 #include "asterisk/aoc.h"
00034 #include "asterisk/utils.h"
00035 #include "asterisk/strings.h"
00036 #include "asterisk/_private.h"
00037 #include "asterisk/cli.h"
00038 #include "asterisk/manager.h"
00039
00040
00041 #define AST_AOC_ENCODED_TYPE_REQUEST (0 << 0)
00042 #define AST_AOC_ENCODED_TYPE_D (1 << 0)
00043 #define AST_AOC_ENCODED_TYPE_E (2 << 0)
00044 #define AST_AOC_ENCODED_TYPE_S (3 << 0)
00045
00046 #define AST_AOC_ENCODED_REQUEST_S (1 << 2)
00047 #define AST_AOC_ENCODED_REQUEST_D (1 << 3)
00048 #define AST_AOC_ENCODED_REQUEST_E (1 << 4)
00049
00050 #define AST_AOC_ENCODED_CHARGE_NA (0 << 5)
00051 #define AST_AOC_ENCODED_CHARGE_FREE (1 << 5)
00052 #define AST_AOC_ENCODED_CHARGE_CURRENCY (2 << 5)
00053 #define AST_AOC_ENCODED_CHARGE_UNIT (3 << 5)
00054
00055 #define AST_AOC_ENCODED_CHARGE_SUBTOTAL (1 << 7)
00056 #define AST_AOC_ENCODED_CHARGE_TOTAL (0 << 7)
00057
00058 #define AST_AOC_ENCODE_VERSION 1
00059
00060
00061 static char aoc_debug_enabled = 0;
00062 static void aoc_display_decoded_debug(const struct ast_aoc_decoded *decoded, int decoding, struct ast_channel *chan);
00063 static int aoc_s_add_entry(struct ast_aoc_decoded *decoded, struct ast_aoc_s_entry *entry);
00064
00065
00066 struct ast_aoc_encoded {
00067 uint8_t version;
00068 uint8_t flags;
00069 uint16_t datalen;
00070 unsigned char data[0];
00071 };
00072
00073
00074 struct ast_aoc_decoded {
00075 enum ast_aoc_type msg_type;
00076 enum ast_aoc_charge_type charge_type;
00077 enum ast_aoc_request request_flag;
00078 enum ast_aoc_total_type total_type;
00079
00080
00081 enum ast_aoc_currency_multiplier multiplier;
00082 unsigned int currency_amount;
00083 char currency_name[AOC_CURRENCY_NAME_SIZE];
00084
00085
00086 int unit_count;
00087 struct ast_aoc_unit_entry unit_list[32];
00088
00089
00090 enum ast_aoc_billing_id billing_id;
00091
00092
00093 struct ast_aoc_charging_association charging_association;
00094
00095
00096 int aoc_s_count;
00097 struct ast_aoc_s_entry aoc_s_entries[10];
00098
00099
00100 char termination_request;
00101 };
00102
00103
00104 enum AOC_IE {
00105 AOC_IE_CURRENCY = 1,
00106 AOC_IE_UNIT = 2,
00107 AOC_IE_BILLING = 3,
00108 AOC_IE_CHARGING_ASSOCIATION = 4,
00109 AOC_IE_RATE = 5,
00110 AOC_IE_TERMINATION_REQUEST = 6,
00111 };
00112
00113
00114 struct aoc_pl_ie_hdr {
00115 uint8_t ie_id;
00116 uint8_t datalen;
00117 char data[0];
00118 } __attribute__((packed));
00119
00120 struct aoc_ie_currency {
00121 uint32_t amount;
00122 uint8_t multiplier;
00123 char name[AOC_CURRENCY_NAME_SIZE];
00124 } __attribute__((packed));
00125
00126 struct aoc_ie_unit {
00127 uint32_t amount;
00128 uint8_t valid_type;
00129 uint8_t valid_amount;
00130 uint8_t type;
00131 } __attribute__((packed));
00132
00133 struct aoc_ie_billing {
00134 uint8_t id;
00135 } __attribute__((packed));
00136
00137 struct aoc_ie_charging_association {
00138 struct ast_aoc_charging_association ca;
00139 } __attribute__((packed));
00140
00141 struct aoc_ie_charging_rate {
00142 struct ast_aoc_s_entry entry;
00143 } __attribute__((packed));
00144
00145 struct ast_aoc_decoded *ast_aoc_create(const enum ast_aoc_type msg_type,
00146 const enum ast_aoc_charge_type charge_type,
00147 const enum ast_aoc_request requests)
00148 {
00149 struct ast_aoc_decoded *decoded = NULL;
00150
00151
00152 if (((unsigned int) charge_type > AST_AOC_CHARGE_UNIT) ||
00153 ((unsigned int) msg_type > AST_AOC_E) ||
00154 ((msg_type == AST_AOC_REQUEST) && !requests)) {
00155
00156 ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object, invalid input\n");
00157 return NULL;
00158 }
00159
00160 if (!(decoded = ast_calloc(1, sizeof(struct ast_aoc_decoded)))) {
00161 ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object \n");
00162 return NULL;
00163 }
00164
00165 decoded->msg_type = msg_type;
00166
00167 if (msg_type == AST_AOC_REQUEST) {
00168 decoded->request_flag = requests;
00169 } else if ((msg_type == AST_AOC_D) || (msg_type == AST_AOC_E)) {
00170 decoded->charge_type = charge_type;
00171 }
00172
00173 return decoded;
00174 }
00175
00176 void *ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
00177 {
00178 ast_free(decoded);
00179 return NULL;
00180 }
00181
00182 void *ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
00183 {
00184 ast_free(encoded);
00185 return NULL;
00186 }
00187
00188 static void aoc_parse_ie_charging_rate(struct ast_aoc_decoded *decoded, const struct aoc_ie_charging_rate *ie)
00189 {
00190 struct ast_aoc_s_entry entry = { 0, };
00191
00192 entry.charged_item = ntohs(ie->entry.charged_item);
00193 entry.rate_type = ntohs(ie->entry.rate_type);
00194
00195 switch (entry.rate_type) {
00196 case AST_AOC_RATE_TYPE_DURATION:
00197 entry.rate.duration.multiplier = ntohs(ie->entry.rate.duration.multiplier);
00198 entry.rate.duration.amount = ntohl(ie->entry.rate.duration.amount);
00199 entry.rate.duration.time = ntohl(ie->entry.rate.duration.time);
00200 entry.rate.duration.time_scale = ntohs(ie->entry.rate.duration.time_scale);
00201 entry.rate.duration.granularity_time = ntohl(ie->entry.rate.duration.granularity_time);
00202 entry.rate.duration.granularity_time_scale = ntohs(ie->entry.rate.duration.granularity_time_scale);
00203 entry.rate.duration.charging_type = ie->entry.rate.duration.charging_type;
00204
00205 if (!ast_strlen_zero(ie->entry.rate.duration.currency_name)) {
00206 ast_copy_string(entry.rate.duration.currency_name,
00207 ie->entry.rate.duration.currency_name,
00208 sizeof(entry.rate.duration.currency_name));
00209 }
00210 break;
00211 case AST_AOC_RATE_TYPE_FLAT:
00212 entry.rate.flat.multiplier = ntohs(ie->entry.rate.flat.multiplier);
00213 entry.rate.flat.amount = ntohl(ie->entry.rate.flat.amount);
00214 if (!ast_strlen_zero(ie->entry.rate.flat.currency_name)) {
00215 ast_copy_string(entry.rate.flat.currency_name,
00216 ie->entry.rate.flat.currency_name,
00217 sizeof(entry.rate.flat.currency_name));
00218 }
00219 break;
00220 case AST_AOC_RATE_TYPE_VOLUME:
00221 entry.rate.volume.multiplier = ntohs(ie->entry.rate.volume.multiplier);
00222 entry.rate.volume.amount = ntohl(ie->entry.rate.volume.amount);
00223 entry.rate.volume.volume_unit = ntohs(ie->entry.rate.volume.volume_unit);
00224 if (!ast_strlen_zero(ie->entry.rate.volume.currency_name)) {
00225 ast_copy_string(entry.rate.volume.currency_name,
00226 ie->entry.rate.volume.currency_name,
00227 sizeof(entry.rate.volume.currency_name));
00228 }
00229 break;
00230 case AST_AOC_RATE_TYPE_SPECIAL_CODE:
00231 entry.rate.special_code = ntohs(ie->entry.rate.special_code);
00232 break;
00233 }
00234
00235 aoc_s_add_entry(decoded, &entry);
00236 }
00237
00238 static int aoc_parse_ie(struct ast_aoc_decoded *decoded, unsigned char *data, unsigned int datalen)
00239 {
00240 enum AOC_IE ie_id;
00241 unsigned int len;
00242
00243 while (datalen >= 2) {
00244 ie_id = data[0];
00245 len = data[1];
00246 if (len > datalen -2) {
00247 ast_log(LOG_ERROR, "AOC information element length exceeds the total message size\n");
00248 return -1;
00249 }
00250
00251 switch(ie_id) {
00252 case AOC_IE_CURRENCY:
00253 if (len == sizeof(struct aoc_ie_currency)) {
00254 struct aoc_ie_currency ie;
00255 memcpy(&ie, data + 2, len);
00256 decoded->currency_amount = ntohl(ie.amount);
00257 decoded->multiplier = ie.multiplier;
00258 memcpy(decoded->currency_name, ie.name, sizeof(decoded->currency_name));
00259 } else {
00260 ast_log(LOG_WARNING, "Received invalid currency ie\n");
00261 }
00262 break;
00263 case AOC_IE_UNIT:
00264 if (len == sizeof(struct aoc_ie_unit)) {
00265 struct aoc_ie_unit ie;
00266 memcpy(&ie, data + 2, len);
00267 ast_aoc_add_unit_entry(decoded, ie.valid_amount, ntohl(ie.amount), ie.valid_type, ie.type);
00268 } else {
00269 ast_log(LOG_WARNING, "Received invalid unit ie\n");
00270 }
00271 break;
00272 case AOC_IE_BILLING:
00273 if (len == sizeof(struct aoc_ie_billing)) {
00274 struct aoc_ie_billing ie;
00275 memcpy(&ie, data + 2, len);
00276 decoded->billing_id = ie.id;
00277 } else {
00278 ast_log(LOG_WARNING, "Received invalid billing ie\n");
00279 }
00280 break;
00281 case AOC_IE_CHARGING_ASSOCIATION:
00282 if (len == sizeof(struct aoc_ie_charging_association)) {
00283 memcpy(&decoded->charging_association, data + 2, sizeof(decoded->charging_association));
00284
00285 if (decoded->charging_association.charging_type == AST_AOC_CHARGING_ASSOCIATION_ID) {
00286 decoded->charging_association.charge.id = ntohl(decoded->charging_association.charge.id);
00287 }
00288 } else {
00289 ast_log(LOG_WARNING, "Received invalid charging association ie\n");
00290 }
00291 break;
00292 case AOC_IE_RATE:
00293 if (len == sizeof(struct aoc_ie_charging_rate)) {
00294 struct aoc_ie_charging_rate ie;
00295 memcpy(&ie, data + 2, len);
00296 aoc_parse_ie_charging_rate(decoded, &ie);
00297 } else {
00298 ast_log(LOG_WARNING, "Received invalid charging rate ie\n");
00299 }
00300 break;
00301 case AOC_IE_TERMINATION_REQUEST:
00302 if (len == 0) {
00303 decoded->termination_request = 1;
00304 } else {
00305 ast_log(LOG_WARNING, "Received invalid termination request ie\n");
00306 }
00307 break;
00308 default:
00309 ast_log(LOG_WARNING, "Unknown AOC Information Element, ignoring.\n");
00310 }
00311
00312 datalen -= (len + 2);
00313 data += (len + 2);
00314 }
00315 return 0;
00316 }
00317
00318 struct ast_aoc_decoded *ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan)
00319 {
00320 struct ast_aoc_decoded *decoded;
00321
00322
00323 if ((size - (sizeof(struct ast_aoc_encoded)) != ntohs(encoded->datalen))) {
00324 ast_log(LOG_WARNING, "Corrupted aoc encoded object, can not decode\n");
00325 return NULL;
00326 }
00327
00328 if (!(decoded = ast_calloc(1, sizeof(struct ast_aoc_decoded)))) {
00329 ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object \n");
00330 return NULL;
00331 }
00332
00333
00334
00335 if ((encoded->flags & AST_AOC_ENCODED_TYPE_S) == AST_AOC_ENCODED_TYPE_S) {
00336 decoded->msg_type = AST_AOC_S;
00337 } else if (encoded->flags & AST_AOC_ENCODED_TYPE_E) {
00338 decoded->msg_type = AST_AOC_E;
00339 } else if (encoded->flags & AST_AOC_ENCODED_TYPE_D) {
00340 decoded->msg_type = AST_AOC_D;
00341 } else {
00342 decoded->msg_type = AST_AOC_REQUEST;
00343 }
00344
00345 if (decoded->msg_type == AST_AOC_REQUEST) {
00346 if (encoded->flags & AST_AOC_ENCODED_REQUEST_S) {
00347 decoded->request_flag |= AST_AOC_REQUEST_S;
00348 }
00349 if (encoded->flags & AST_AOC_ENCODED_REQUEST_D) {
00350 decoded->request_flag |= AST_AOC_REQUEST_D;
00351 }
00352 if (encoded->flags & AST_AOC_ENCODED_REQUEST_E) {
00353 decoded->request_flag |= AST_AOC_REQUEST_E;
00354 }
00355 } else if ((decoded->msg_type == AST_AOC_D) || (decoded->msg_type == AST_AOC_E)) {
00356 if ((encoded->flags & AST_AOC_ENCODED_CHARGE_UNIT) == AST_AOC_ENCODED_CHARGE_UNIT) {
00357 decoded->charge_type = AST_AOC_CHARGE_UNIT;
00358 } else if ((encoded->flags & AST_AOC_ENCODED_CHARGE_CURRENCY) == AST_AOC_ENCODED_CHARGE_CURRENCY) {
00359 decoded->charge_type = AST_AOC_CHARGE_CURRENCY;
00360 } else if ((encoded->flags & AST_AOC_ENCODED_CHARGE_FREE) == AST_AOC_ENCODED_CHARGE_FREE) {
00361 decoded->charge_type = AST_AOC_CHARGE_FREE;
00362 } else {
00363 decoded->charge_type = AST_AOC_CHARGE_NA;
00364 }
00365
00366 if (encoded->flags & AST_AOC_ENCODED_CHARGE_SUBTOTAL) {
00367 decoded->total_type = AST_AOC_SUBTOTAL;
00368 }
00369 }
00370
00371
00372 aoc_parse_ie(decoded, encoded->data, ntohs(encoded->datalen));
00373
00374 if (aoc_debug_enabled) {
00375 aoc_display_decoded_debug(decoded, 1, chan);
00376 }
00377
00378 return decoded;
00379 }
00380
00381 struct aoc_ie_data {
00382 unsigned char buf[1024];
00383 int pos;
00384 };
00385
00386
00387
00388
00389
00390
00391 static int aoc_append_ie(struct aoc_ie_data *ied, unsigned short ie_id, const void *data, unsigned short datalen)
00392 {
00393 if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00394 ast_log(LOG_WARNING, "Failure to append AOC information element, out of space \n");
00395 return -1;
00396 }
00397 ied->buf[ied->pos++] = ie_id;
00398 ied->buf[ied->pos++] = datalen;
00399 if (datalen) {
00400 memcpy(ied->buf + ied->pos, data, datalen);
00401 ied->pos += datalen;
00402 }
00403 return 0;
00404 }
00405
00406 static void aoc_create_ie_data_charging_rate(const struct ast_aoc_s_entry *entry, struct aoc_ie_charging_rate *ie)
00407 {
00408 ie->entry.charged_item = htons(entry->charged_item);
00409 ie->entry.rate_type = htons(entry->rate_type);
00410
00411 switch (entry->rate_type) {
00412 case AST_AOC_RATE_TYPE_DURATION:
00413 ie->entry.rate.duration.multiplier = htons(entry->rate.duration.multiplier);
00414 ie->entry.rate.duration.amount = htonl(entry->rate.duration.amount);
00415 ie->entry.rate.duration.time = htonl(entry->rate.duration.time);
00416 ie->entry.rate.duration.time_scale = htons(entry->rate.duration.time_scale);
00417 ie->entry.rate.duration.granularity_time = htonl(entry->rate.duration.granularity_time);
00418 ie->entry.rate.duration.granularity_time_scale = htons(entry->rate.duration.granularity_time_scale);
00419 ie->entry.rate.duration.charging_type = entry->rate.duration.charging_type;
00420
00421 if (!ast_strlen_zero(entry->rate.duration.currency_name)) {
00422 ast_copy_string(ie->entry.rate.duration.currency_name,
00423 entry->rate.duration.currency_name,
00424 sizeof(ie->entry.rate.duration.currency_name));
00425 }
00426 break;
00427 case AST_AOC_RATE_TYPE_FLAT:
00428 ie->entry.rate.flat.multiplier = htons(entry->rate.flat.multiplier);
00429 ie->entry.rate.flat.amount = htonl(entry->rate.flat.amount);
00430 if (!ast_strlen_zero(entry->rate.flat.currency_name)) {
00431 ast_copy_string(ie->entry.rate.flat.currency_name,
00432 entry->rate.flat.currency_name,
00433 sizeof(ie->entry.rate.flat.currency_name));
00434 }
00435 break;
00436 case AST_AOC_RATE_TYPE_VOLUME:
00437 ie->entry.rate.volume.multiplier = htons(entry->rate.volume.multiplier);
00438 ie->entry.rate.volume.amount = htonl(entry->rate.volume.amount);
00439 ie->entry.rate.volume.volume_unit = htons(entry->rate.volume.volume_unit);
00440 if (!ast_strlen_zero(entry->rate.volume.currency_name)) {
00441 ast_copy_string(ie->entry.rate.volume.currency_name,
00442 entry->rate.volume.currency_name,
00443 sizeof(ie->entry.rate.volume.currency_name));
00444 }
00445 break;
00446 case AST_AOC_RATE_TYPE_SPECIAL_CODE:
00447 ie->entry.rate.special_code = htons(entry->rate.special_code);
00448 break;
00449 }
00450
00451 }
00452 static void aoc_create_ie_data(struct ast_aoc_decoded *decoded, struct aoc_ie_data *ied)
00453 {
00454 ied->pos = 0;
00455
00456 if (decoded->currency_amount) {
00457 struct aoc_ie_currency ie = {
00458 .amount = htonl(decoded->currency_amount),
00459 .multiplier = decoded->multiplier,
00460 .name = { 0, },
00461 };
00462
00463 if (!ast_strlen_zero(decoded->currency_name)) {
00464 ast_copy_string(ie.name, decoded->currency_name, sizeof(ie.name));
00465 }
00466
00467 aoc_append_ie(ied, AOC_IE_CURRENCY, (const void *) &ie, sizeof(ie));
00468 }
00469
00470 if (decoded->unit_count) {
00471 struct aoc_ie_unit ie = { 0 };
00472 int i;
00473
00474 for (i = 0; i < decoded->unit_count; i++) {
00475 ie.valid_amount = decoded->unit_list[i].valid_amount;
00476 ie.amount = htonl(decoded->unit_list[i].amount);
00477 ie.valid_type = decoded->unit_list[i].valid_type;
00478 ie.type = decoded->unit_list[i].type;
00479 aoc_append_ie(ied, AOC_IE_UNIT, (const void *) &ie, sizeof(ie));
00480 }
00481 }
00482
00483 if (decoded->billing_id) {
00484 struct aoc_ie_billing ie;
00485 ie.id = decoded->billing_id;
00486 aoc_append_ie(ied, AOC_IE_BILLING, (const void *) &ie, sizeof(ie));
00487 }
00488
00489 if (decoded->charging_association.charging_type != AST_AOC_CHARGING_ASSOCIATION_NA) {
00490 struct aoc_ie_charging_association ie;
00491 memset(&ie, 0, sizeof(ie));
00492 ie.ca.charging_type = decoded->charging_association.charging_type;
00493 if (decoded->charging_association.charging_type == AST_AOC_CHARGING_ASSOCIATION_NUMBER) {
00494 ie.ca.charge.number.plan = decoded->charging_association.charge.number.plan;
00495 ast_copy_string(ie.ca.charge.number.number,
00496 decoded->charging_association.charge.number.number,
00497 sizeof(ie.ca.charge.number.number));
00498 } else if (decoded->charging_association.charging_type == AST_AOC_CHARGING_ASSOCIATION_ID) {
00499 ie.ca.charge.id = htonl(decoded->charging_association.charge.id);
00500 }
00501 aoc_append_ie(ied, AOC_IE_CHARGING_ASSOCIATION, (const void *) &ie, sizeof(ie));
00502 }
00503
00504 if (decoded->aoc_s_count) {
00505 struct aoc_ie_charging_rate ie;
00506 int i;
00507 for (i = 0; i < decoded->aoc_s_count; i++) {
00508 memset(&ie, 0, sizeof(ie));
00509 aoc_create_ie_data_charging_rate(&decoded->aoc_s_entries[i], &ie);
00510 aoc_append_ie(ied, AOC_IE_RATE, (const void *) &ie, sizeof(ie));
00511 }
00512 }
00513
00514 if (decoded->termination_request) {
00515 aoc_append_ie(ied, AOC_IE_TERMINATION_REQUEST, NULL, 0);
00516 }
00517 }
00518
00519 struct ast_aoc_encoded *ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan)
00520 {
00521 struct aoc_ie_data ied;
00522 struct ast_aoc_encoded *encoded = NULL;
00523 size_t size = 0;
00524
00525 if (!decoded || !out_size) {
00526 return NULL;
00527 }
00528
00529 *out_size = 0;
00530
00531
00532
00533
00534 aoc_create_ie_data(decoded, &ied);
00535
00536 size = sizeof(struct ast_aoc_encoded) + ied.pos;
00537
00538 if (!(encoded = ast_calloc(1, size))) {
00539 ast_log(LOG_WARNING, "Failed to create ast_aoc_encoded object during decode routine. \n");
00540 return NULL;
00541 }
00542
00543
00544 if (ied.pos) {
00545
00546 memcpy(encoded->data, ied.buf, ied.pos);
00547 encoded->datalen = htons(ied.pos);
00548 }
00549
00550
00551 switch (decoded->msg_type) {
00552 case AST_AOC_S:
00553 encoded->flags = AST_AOC_ENCODED_TYPE_S;
00554 break;
00555 case AST_AOC_D:
00556 encoded->flags = AST_AOC_ENCODED_TYPE_D;
00557 break;
00558 case AST_AOC_E:
00559 encoded->flags = AST_AOC_ENCODED_TYPE_E;
00560 break;
00561 case AST_AOC_REQUEST:
00562 encoded->flags = AST_AOC_ENCODED_TYPE_REQUEST;
00563 default:
00564 break;
00565 }
00566
00567
00568 if (decoded->msg_type == AST_AOC_REQUEST) {
00569 if (decoded->request_flag & AST_AOC_REQUEST_S) {
00570 encoded->flags |= AST_AOC_ENCODED_REQUEST_S;
00571 }
00572 if (decoded->request_flag & AST_AOC_REQUEST_D) {
00573 encoded->flags |= AST_AOC_ENCODED_REQUEST_D;
00574 }
00575 if (decoded->request_flag & AST_AOC_REQUEST_E) {
00576 encoded->flags |= AST_AOC_ENCODED_REQUEST_E;
00577 }
00578 } else if ((decoded->msg_type == AST_AOC_D) || (decoded->msg_type == AST_AOC_E)) {
00579 switch (decoded->charge_type) {
00580 case AST_AOC_CHARGE_UNIT:
00581 encoded->flags |= AST_AOC_ENCODED_CHARGE_UNIT;
00582 break;
00583 case AST_AOC_CHARGE_CURRENCY:
00584 encoded->flags |= AST_AOC_ENCODED_CHARGE_CURRENCY;
00585 break;
00586 case AST_AOC_CHARGE_FREE:
00587 encoded->flags |= AST_AOC_ENCODED_CHARGE_FREE;
00588 case AST_AOC_CHARGE_NA:
00589 default:
00590 encoded->flags |= AST_AOC_ENCODED_CHARGE_NA;
00591 break;
00592 }
00593
00594 if (decoded->total_type == AST_AOC_SUBTOTAL) {
00595 encoded->flags |= AST_AOC_ENCODED_CHARGE_SUBTOTAL;
00596 }
00597 }
00598
00599
00600 encoded->version = AST_AOC_ENCODE_VERSION;
00601
00602
00603 *out_size = size;
00604
00605 if (aoc_debug_enabled) {
00606 aoc_display_decoded_debug(decoded, 0, chan);
00607 }
00608
00609 return encoded;
00610 }
00611
00612 static int aoc_s_add_entry(struct ast_aoc_decoded *decoded, struct ast_aoc_s_entry *entry)
00613 {
00614 if (decoded->aoc_s_count >= ARRAY_LEN(decoded->aoc_s_entries)) {
00615 return -1;
00616 }
00617
00618 decoded->aoc_s_entries[decoded->aoc_s_count] = *entry;
00619 decoded->aoc_s_count++;
00620
00621 return 0;
00622 }
00623
00624
00625 unsigned int ast_aoc_s_get_count(struct ast_aoc_decoded *decoded)
00626 {
00627 return decoded->aoc_s_count;
00628 }
00629
00630 const struct ast_aoc_s_entry *ast_aoc_s_get_rate_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
00631 {
00632 if (entry_number >= decoded->aoc_s_count) {
00633 return NULL;
00634 }
00635
00636 return (const struct ast_aoc_s_entry *) &decoded->aoc_s_entries[entry_number];
00637 }
00638
00639 int ast_aoc_s_add_rate_duration(struct ast_aoc_decoded *decoded,
00640 enum ast_aoc_s_charged_item charged_item,
00641 unsigned int amount,
00642 enum ast_aoc_currency_multiplier multiplier,
00643 const char *currency_name,
00644 unsigned long time,
00645 enum ast_aoc_time_scale time_scale,
00646 unsigned long granularity_time,
00647 enum ast_aoc_time_scale granularity_time_scale,
00648 int step_function)
00649 {
00650
00651 struct ast_aoc_s_entry entry = { 0, };
00652
00653 entry.charged_item = charged_item;
00654 entry.rate_type = AST_AOC_RATE_TYPE_DURATION;
00655 entry.rate.duration.amount = amount;
00656 entry.rate.duration.multiplier = multiplier;
00657 entry.rate.duration.time = time;
00658 entry.rate.duration.time_scale = time_scale;
00659 entry.rate.duration.granularity_time = granularity_time;
00660 entry.rate.duration.granularity_time_scale = granularity_time_scale;
00661 entry.rate.duration.charging_type = step_function ? 1 : 0;
00662
00663 if (!ast_strlen_zero(currency_name)) {
00664 ast_copy_string(entry.rate.duration.currency_name, currency_name, sizeof(entry.rate.duration.currency_name));
00665 }
00666
00667 return aoc_s_add_entry(decoded, &entry);
00668 }
00669
00670 int ast_aoc_s_add_rate_flat(struct ast_aoc_decoded *decoded,
00671 enum ast_aoc_s_charged_item charged_item,
00672 unsigned int amount,
00673 enum ast_aoc_currency_multiplier multiplier,
00674 const char *currency_name)
00675 {
00676 struct ast_aoc_s_entry entry = { 0, };
00677
00678 entry.charged_item = charged_item;
00679 entry.rate_type = AST_AOC_RATE_TYPE_FLAT;
00680 entry.rate.flat.amount = amount;
00681 entry.rate.flat.multiplier = multiplier;
00682
00683 if (!ast_strlen_zero(currency_name)) {
00684 ast_copy_string(entry.rate.flat.currency_name, currency_name, sizeof(entry.rate.flat.currency_name));
00685 }
00686
00687 return aoc_s_add_entry(decoded, &entry);
00688 }
00689
00690
00691 int ast_aoc_s_add_rate_volume(struct ast_aoc_decoded *decoded,
00692 enum ast_aoc_s_charged_item charged_item,
00693 enum ast_aoc_volume_unit volume_unit,
00694 unsigned int amount,
00695 enum ast_aoc_currency_multiplier multiplier,
00696 const char *currency_name)
00697 {
00698 struct ast_aoc_s_entry entry = { 0, };
00699
00700 entry.charged_item = charged_item;
00701 entry.rate_type = AST_AOC_RATE_TYPE_VOLUME;
00702 entry.rate.volume.multiplier = multiplier;
00703 entry.rate.volume.amount = amount;
00704 entry.rate.volume.volume_unit = volume_unit;
00705
00706 if (!ast_strlen_zero(currency_name)) {
00707 ast_copy_string(entry.rate.volume.currency_name, currency_name, sizeof(entry.rate.volume.currency_name));
00708 }
00709
00710 return aoc_s_add_entry(decoded, &entry);
00711 }
00712
00713 int ast_aoc_s_add_rate_special_charge_code(struct ast_aoc_decoded *decoded,
00714 enum ast_aoc_s_charged_item charged_item,
00715 unsigned int code)
00716 {
00717 struct ast_aoc_s_entry entry = { 0, };
00718
00719 entry.charged_item = charged_item;
00720 entry.rate_type = AST_AOC_RATE_TYPE_SPECIAL_CODE;
00721 entry.rate.special_code = code;
00722
00723 return aoc_s_add_entry(decoded, &entry);
00724 }
00725
00726 int ast_aoc_s_add_rate_free(struct ast_aoc_decoded *decoded,
00727 enum ast_aoc_s_charged_item charged_item,
00728 int from_beginning)
00729 {
00730 struct ast_aoc_s_entry entry = { 0, };
00731
00732 entry.charged_item = charged_item;
00733 entry.rate_type = from_beginning ? AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING : AST_AOC_RATE_TYPE_FREE;
00734
00735 return aoc_s_add_entry(decoded, &entry);
00736 }
00737
00738 int ast_aoc_s_add_rate_na(struct ast_aoc_decoded *decoded,
00739 enum ast_aoc_s_charged_item charged_item)
00740 {
00741 struct ast_aoc_s_entry entry = { 0, };
00742
00743 entry.charged_item = charged_item;
00744 entry.rate_type = AST_AOC_RATE_TYPE_NA;
00745
00746 return aoc_s_add_entry(decoded, &entry);
00747 }
00748
00749 int ast_aoc_s_add_special_arrangement(struct ast_aoc_decoded *decoded,
00750 unsigned int code)
00751 {
00752 struct ast_aoc_s_entry entry = { 0, };
00753
00754 entry.charged_item = AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
00755 entry.rate_type = AST_AOC_RATE_TYPE_SPECIAL_CODE;
00756 entry.rate.special_code = code;
00757
00758 return aoc_s_add_entry(decoded, &entry);
00759 }
00760
00761 enum ast_aoc_type ast_aoc_get_msg_type(struct ast_aoc_decoded *decoded)
00762 {
00763 return decoded->msg_type;
00764 }
00765
00766 enum ast_aoc_charge_type ast_aoc_get_charge_type(struct ast_aoc_decoded *decoded)
00767 {
00768 return decoded->charge_type;
00769 }
00770
00771 enum ast_aoc_request ast_aoc_get_request(struct ast_aoc_decoded *decoded)
00772 {
00773 return decoded->request_flag;
00774 }
00775
00776 int ast_aoc_set_total_type(struct ast_aoc_decoded *decoded,
00777 const enum ast_aoc_total_type type)
00778 {
00779 decoded->total_type = type;
00780 return 0;
00781 }
00782
00783 enum ast_aoc_total_type ast_aoc_get_total_type(struct ast_aoc_decoded *decoded)
00784 {
00785 return decoded->total_type;
00786 }
00787
00788 int ast_aoc_set_currency_info(struct ast_aoc_decoded *decoded,
00789 const unsigned int amount,
00790 const enum ast_aoc_currency_multiplier multiplier,
00791 const char *name)
00792 {
00793
00794 if (!ast_strlen_zero(name)) {
00795 ast_copy_string(decoded->currency_name, name, sizeof(decoded->currency_name));
00796 }
00797
00798 decoded->currency_amount = amount;
00799
00800 if (multiplier && (multiplier < AST_AOC_MULT_NUM_ENTRIES)) {
00801 decoded->multiplier = multiplier;
00802 } else {
00803 decoded->multiplier = AST_AOC_MULT_ONE;
00804 }
00805
00806 return 0;
00807 }
00808
00809 unsigned int ast_aoc_get_currency_amount(struct ast_aoc_decoded *decoded)
00810 {
00811 return decoded->currency_amount;
00812 }
00813
00814 enum ast_aoc_currency_multiplier ast_aoc_get_currency_multiplier(struct ast_aoc_decoded *decoded)
00815 {
00816 return decoded->multiplier;
00817 }
00818
00819 const char *ast_aoc_get_currency_multiplier_decimal(struct ast_aoc_decoded *decoded)
00820 {
00821 switch (decoded->multiplier) {
00822 case AST_AOC_MULT_ONETHOUSANDTH:
00823 return "0.001";
00824 case AST_AOC_MULT_ONEHUNDREDTH:
00825 return "0.01";
00826 case AST_AOC_MULT_ONETENTH:
00827 return "0.1";
00828 case AST_AOC_MULT_ONE:
00829 return "1.0";
00830 case AST_AOC_MULT_TEN:
00831 return "10.0";
00832 case AST_AOC_MULT_HUNDRED:
00833 return "100.0";
00834 case AST_AOC_MULT_THOUSAND:
00835 return "1000.0";
00836 default:
00837 return "1.0";
00838 }
00839 }
00840
00841 const char *ast_aoc_get_currency_name(struct ast_aoc_decoded *decoded)
00842 {
00843 return decoded->currency_name;
00844 }
00845
00846 int ast_aoc_add_unit_entry(struct ast_aoc_decoded *decoded,
00847 const unsigned int amount_is_present,
00848 const unsigned int amount,
00849 const unsigned int type_is_present,
00850 const unsigned int type)
00851 {
00852 if ((decoded->msg_type == AST_AOC_REQUEST) ||
00853 (decoded->unit_count >= ARRAY_LEN(decoded->unit_list))) {
00854 return -1;
00855 }
00856
00857 if (!amount_is_present && !type_is_present) {
00858 return -1;
00859 }
00860
00861 decoded->unit_list[decoded->unit_count].valid_amount = amount_is_present;
00862 if (amount_is_present) {
00863 decoded->unit_list[decoded->unit_count].amount = amount;
00864 } else {
00865 decoded->unit_list[decoded->unit_count].amount = 0;
00866 }
00867
00868 decoded->unit_list[decoded->unit_count].valid_type = type_is_present;
00869 if (type_is_present) {
00870 decoded->unit_list[decoded->unit_count].type = type;
00871 } else {
00872 decoded->unit_list[decoded->unit_count].type = 0;
00873 }
00874 decoded->unit_count++;
00875
00876 return 0;
00877 }
00878
00879 const struct ast_aoc_unit_entry *ast_aoc_get_unit_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
00880 {
00881 if (entry_number >= decoded->unit_count) {
00882 return NULL;
00883 }
00884
00885 return (const struct ast_aoc_unit_entry *) &decoded->unit_list[entry_number];
00886 }
00887
00888 unsigned int ast_aoc_get_unit_count(struct ast_aoc_decoded *decoded)
00889 {
00890 return decoded->unit_count;
00891 }
00892
00893 int ast_aoc_set_billing_id(struct ast_aoc_decoded *decoded, const enum ast_aoc_billing_id id)
00894 {
00895 if ((id >= AST_AOC_BILLING_NUM_ENTRIES) || (id < AST_AOC_BILLING_NA)) {
00896 return -1;
00897 }
00898
00899 decoded->billing_id = id;
00900
00901 return 0;
00902 }
00903
00904 enum ast_aoc_billing_id ast_aoc_get_billing_id(struct ast_aoc_decoded *decoded)
00905 {
00906 return decoded->billing_id;
00907 }
00908
00909 int ast_aoc_set_association_id(struct ast_aoc_decoded *decoded, const int id)
00910 {
00911 if (decoded->msg_type != AST_AOC_E) {
00912 return -1;
00913 }
00914 memset(&decoded->charging_association, 0, sizeof(decoded->charging_association));
00915 decoded->charging_association.charging_type = AST_AOC_CHARGING_ASSOCIATION_ID;
00916 decoded->charging_association.charge.id = id;
00917 return 0;
00918 }
00919
00920 const struct ast_aoc_charging_association *ast_aoc_get_association_info(struct ast_aoc_decoded *decoded)
00921 {
00922 return &decoded->charging_association;
00923 }
00924
00925 int ast_aoc_set_association_number(struct ast_aoc_decoded *decoded, const char *num, uint8_t plan)
00926 {
00927 if ((decoded->msg_type != AST_AOC_E) || ast_strlen_zero(num)) {
00928 return -1;
00929 }
00930 memset(&decoded->charging_association, 0, sizeof(decoded->charging_association));
00931 decoded->charging_association.charging_type = AST_AOC_CHARGING_ASSOCIATION_NUMBER;
00932 decoded->charging_association.charge.number.plan = plan;
00933 ast_copy_string(decoded->charging_association.charge.number.number, num, sizeof(decoded->charging_association.charge.number.number));
00934
00935 return 0;
00936 }
00937
00938 int ast_aoc_set_termination_request(struct ast_aoc_decoded *decoded)
00939 {
00940 if (decoded->msg_type != AST_AOC_REQUEST) {
00941 return -1;
00942 }
00943 decoded->termination_request = 1;
00944
00945 return 0;
00946 }
00947
00948 int ast_aoc_get_termination_request(struct ast_aoc_decoded *decoded)
00949 {
00950 return decoded->termination_request;
00951 }
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962 static const char *aoc_volume_unit_str(enum ast_aoc_volume_unit value)
00963 {
00964 const char *str;
00965
00966 switch (value) {
00967 default:
00968 case AST_AOC_VOLUME_UNIT_OCTET:
00969 str = "Octet";
00970 break;
00971 case AST_AOC_VOLUME_UNIT_SEGMENT:
00972 str = "Segment";
00973 break;
00974 case AST_AOC_VOLUME_UNIT_MESSAGE:
00975 str = "Message";
00976 break;
00977 }
00978 return str;
00979 }
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990 static const char *aoc_charged_item_str(enum ast_aoc_s_charged_item value)
00991 {
00992 const char *str;
00993
00994 switch (value) {
00995 default:
00996 case AST_AOC_CHARGED_ITEM_NA:
00997 str = "NotAvailable";
00998 break;
00999 case AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT:
01000 str = "SpecialArrangement";
01001 break;
01002 case AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION:
01003 str = "BasicCommunication";
01004 break;
01005 case AST_AOC_CHARGED_ITEM_CALL_ATTEMPT:
01006 str = "CallAttempt";
01007 break;
01008 case AST_AOC_CHARGED_ITEM_CALL_SETUP:
01009 str = "CallSetup";
01010 break;
01011 case AST_AOC_CHARGED_ITEM_USER_USER_INFO:
01012 str = "UserUserInfo";
01013 break;
01014 case AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE:
01015 str = "SupplementaryService";
01016 break;
01017 }
01018 return str;
01019 }
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030 static const char *aoc_type_of_totaling_str(enum ast_aoc_total_type value)
01031 {
01032 const char *str;
01033
01034 switch (value) {
01035 default:
01036 case AST_AOC_SUBTOTAL:
01037 str = "SubTotal";
01038 break;
01039 case AST_AOC_TOTAL:
01040 str = "Total";
01041 break;
01042 }
01043 return str;
01044 }
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055 static const char *aoc_rate_type_str(enum ast_aoc_s_rate_type value)
01056 {
01057 const char *str;
01058
01059 switch (value) {
01060 default:
01061 case AST_AOC_RATE_TYPE_NA:
01062 str = "NotAvailable";
01063 break;
01064 case AST_AOC_RATE_TYPE_FREE:
01065 str = "Free";
01066 break;
01067 case AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING:
01068 str = "FreeFromBeginning";
01069 break;
01070 case AST_AOC_RATE_TYPE_DURATION:
01071 str = "Duration";
01072 break;
01073 case AST_AOC_RATE_TYPE_FLAT:
01074 str = "Flat";
01075 break;
01076 case AST_AOC_RATE_TYPE_VOLUME:
01077 str = "Volume";
01078 break;
01079 case AST_AOC_RATE_TYPE_SPECIAL_CODE:
01080 str = "SpecialCode";
01081 break;
01082 }
01083 return str;
01084 }
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095 static const char *aoc_scale_str(enum ast_aoc_time_scale value)
01096 {
01097 const char *str;
01098
01099 switch (value) {
01100 default:
01101 case AST_AOC_TIME_SCALE_HUNDREDTH_SECOND:
01102 str = "OneHundredthSecond";
01103 break;
01104 case AST_AOC_TIME_SCALE_TENTH_SECOND:
01105 str = "OneTenthSecond";
01106 break;
01107 case AST_AOC_TIME_SCALE_SECOND:
01108 str = "Second";
01109 break;
01110 case AST_AOC_TIME_SCALE_TEN_SECOND:
01111 str = "TenSeconds";
01112 break;
01113 case AST_AOC_TIME_SCALE_MINUTE:
01114 str = "Minute";
01115 break;
01116 case AST_AOC_TIME_SCALE_HOUR:
01117 str = "Hour";
01118 break;
01119 case AST_AOC_TIME_SCALE_DAY:
01120 str = "Day";
01121 break;
01122 }
01123 return str;
01124 }
01125
01126 static const char *aoc_charge_type_str(enum ast_aoc_charge_type value)
01127 {
01128 const char *str;
01129
01130 switch (value) {
01131 default:
01132 case AST_AOC_CHARGE_NA:
01133 str = "NotAvailable";
01134 break;
01135 case AST_AOC_CHARGE_FREE:
01136 str = "Free";
01137 break;
01138 case AST_AOC_CHARGE_CURRENCY:
01139 str = "Currency";
01140 break;
01141 case AST_AOC_CHARGE_UNIT:
01142 str = "Units";
01143 break;
01144 }
01145
01146 return str;
01147 }
01148
01149 static const char *aoc_multiplier_str(enum ast_aoc_currency_multiplier mult)
01150 {
01151 switch (mult) {
01152 case AST_AOC_MULT_ONETHOUSANDTH:
01153 return "1/1000";
01154 case AST_AOC_MULT_ONEHUNDREDTH:
01155 return "1/100";
01156 case AST_AOC_MULT_ONETENTH:
01157 return "1/10";
01158 case AST_AOC_MULT_ONE:
01159 return "1";
01160 case AST_AOC_MULT_TEN:
01161 return "10";
01162 case AST_AOC_MULT_HUNDRED:
01163 return "100";
01164 case AST_AOC_MULT_THOUSAND:
01165 return "1000";
01166 case AST_AOC_MULT_NUM_ENTRIES:
01167 break;
01168 }
01169 return "1";
01170 }
01171
01172 static const char *aoc_billingid_str(enum ast_aoc_billing_id billing_id)
01173 {
01174 switch (billing_id) {
01175 case AST_AOC_BILLING_NORMAL:
01176 return "Normal";
01177 case AST_AOC_BILLING_REVERSE_CHARGE:
01178 return "Reverse";
01179 case AST_AOC_BILLING_CREDIT_CARD:
01180 return "CreditCard";
01181 case AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL:
01182 return "CallForwardingUnconditional";
01183 case AST_AOC_BILLING_CALL_FWD_BUSY:
01184 return "CallForwardingBusy";
01185 case AST_AOC_BILLING_CALL_FWD_NO_REPLY:
01186 return "CallForwardingNoReply";
01187 case AST_AOC_BILLING_CALL_DEFLECTION:
01188 return "CallDeflection";
01189 case AST_AOC_BILLING_CALL_TRANSFER:
01190 return "CallTransfer";
01191 case AST_AOC_BILLING_NA:
01192 return "NotAvailable";
01193 case AST_AOC_BILLING_NUM_ENTRIES:
01194 break;
01195 }
01196 return "NotAvailable";
01197 }
01198
01199 int ast_aoc_test_encode_decode_match(struct ast_aoc_decoded *decoded)
01200 {
01201 struct ast_aoc_decoded *new_decoded = NULL;
01202 struct ast_aoc_encoded *encoded = NULL;
01203 size_t size;
01204 int res = 0;
01205
01206 if (!(encoded = ast_aoc_encode(decoded, &size, NULL))) {
01207 return -1;
01208 }
01209
01210 if (!(new_decoded = ast_aoc_decode(encoded, size, NULL))) {
01211 ast_free(encoded);
01212 return -1;
01213 }
01214
01215 if (memcmp(new_decoded, decoded, sizeof(struct ast_aoc_decoded))) {
01216 res = -1;
01217 }
01218
01219 ast_aoc_destroy_decoded(new_decoded);
01220 ast_aoc_destroy_encoded(encoded);
01221 return res;
01222 }
01223
01224 static char *aoc_cli_debug_enable(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01225 {
01226 switch (cmd) {
01227 case CLI_INIT:
01228 e->command = "aoc set debug";
01229 e->usage =
01230 "Usage: 'aoc set debug on' to enable aoc debug, 'aoc set debug off' to disable debug.\n";
01231 return NULL;
01232 case CLI_GENERATE:
01233 return NULL;
01234 case CLI_HANDLER:
01235 if (a->argc != 4) {
01236 return CLI_SHOWUSAGE;
01237 } else if(ast_true(a->argv[3])) {
01238 ast_cli(a->fd, "aoc debug enabled\n");
01239 aoc_debug_enabled = 1;
01240 } else if (ast_false(a->argv[3])) {
01241 ast_cli(a->fd, "aoc debug disabled\n");
01242 aoc_debug_enabled = 0;
01243 } else {
01244 return CLI_SHOWUSAGE;
01245 }
01246 }
01247
01248 return CLI_SUCCESS;
01249 }
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264 static void aoc_time_str(struct ast_str **msg, const char *prefix, const char *name, unsigned long time, enum ast_aoc_time_scale scale)
01265 {
01266 ast_str_append(msg, 0, "%s/%s/Length: %lu\r\n", prefix, name, time);
01267 ast_str_append(msg, 0, "%s/%s/Scale: %s\r\n", prefix, name,
01268 aoc_scale_str(scale));
01269 }
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283 static void aoc_amount_str(struct ast_str **msg, const char *prefix, unsigned int amount, enum ast_aoc_currency_multiplier mult)
01284 {
01285 static const char name[] = "Amount";
01286
01287 ast_str_append(msg, 0, "%s/%s/Cost: %u\r\n", prefix, name, amount);
01288 ast_str_append(msg, 0, "%s/%s/Multiplier: %s\r\n", prefix, name,
01289 aoc_multiplier_str(mult));
01290 }
01291
01292 static void aoc_request_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan, struct ast_str **msg)
01293 {
01294 if (chan) {
01295 ast_str_append(msg, 0, "Channel: %s\r\n", chan->name);
01296 ast_str_append(msg, 0, "UniqueID: %s\r\n", chan->uniqueid);
01297 }
01298
01299 if (decoded->request_flag) {
01300 ast_str_append(msg, 0, "AOCRequest:");
01301 if (decoded->request_flag & AST_AOC_REQUEST_S) {
01302 ast_str_append(msg, 0, "S");
01303 }
01304 if (decoded->request_flag & AST_AOC_REQUEST_D) {
01305 ast_str_append(msg, 0, "D");
01306 }
01307 if (decoded->request_flag & AST_AOC_REQUEST_E) {
01308 ast_str_append(msg, 0, "E");
01309 }
01310 ast_str_append(msg, 0, "\r\n");
01311
01312 } else {
01313 ast_str_append(msg, 0, "AOCRequest: NONE\r\n");
01314 }
01315 }
01316
01317 static void aoc_s_event(const struct ast_aoc_decoded *decoded, struct ast_channel *owner, struct ast_str **msg)
01318 {
01319 const char *rate_str;
01320 char prefix[32];
01321 int idx;
01322
01323 if (owner) {
01324 ast_str_append(msg, 0, "Channel: %s\r\n", owner->name);
01325 ast_str_append(msg, 0, "UniqueID: %s\r\n", owner->uniqueid);
01326 }
01327
01328 ast_str_append(msg, 0, "NumberRates: %d\r\n", decoded->aoc_s_count);
01329 for (idx = 0; idx < decoded->aoc_s_count; ++idx) {
01330 snprintf(prefix, sizeof(prefix), "Rate(%d)", idx);
01331
01332 ast_str_append(msg, 0, "%s/Chargeable: %s\r\n", prefix,
01333 aoc_charged_item_str(decoded->aoc_s_entries[idx].charged_item));
01334 if (decoded->aoc_s_entries[idx].charged_item == AST_AOC_CHARGED_ITEM_NA) {
01335 continue;
01336 }
01337 rate_str = aoc_rate_type_str(decoded->aoc_s_entries[idx].rate_type);
01338 ast_str_append(msg, 0, "%s/Type: %s\r\n", prefix, rate_str);
01339 switch (decoded->aoc_s_entries[idx].rate_type) {
01340 case AST_AOC_RATE_TYPE_DURATION:
01341 strcat(prefix, "/");
01342 strcat(prefix, rate_str);
01343 ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
01344 decoded->aoc_s_entries[idx].rate.duration.currency_name);
01345 aoc_amount_str(msg, prefix,
01346 decoded->aoc_s_entries[idx].rate.duration.amount,
01347 decoded->aoc_s_entries[idx].rate.duration.multiplier);
01348 ast_str_append(msg, 0, "%s/ChargingType: %s\r\n", prefix,
01349 decoded->aoc_s_entries[idx].rate.duration.charging_type ?
01350 "StepFunction" : "ContinuousCharging");
01351 aoc_time_str(msg, prefix, "Time",
01352 decoded->aoc_s_entries[idx].rate.duration.time,
01353 decoded->aoc_s_entries[idx].rate.duration.time_scale);
01354 if (decoded->aoc_s_entries[idx].rate.duration.granularity_time) {
01355 aoc_time_str(msg, prefix, "Granularity",
01356 decoded->aoc_s_entries[idx].rate.duration.granularity_time,
01357 decoded->aoc_s_entries[idx].rate.duration.granularity_time_scale);
01358 }
01359 break;
01360 case AST_AOC_RATE_TYPE_FLAT:
01361 strcat(prefix, "/");
01362 strcat(prefix, rate_str);
01363 ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
01364 decoded->aoc_s_entries[idx].rate.flat.currency_name);
01365 aoc_amount_str(msg, prefix,
01366 decoded->aoc_s_entries[idx].rate.flat.amount,
01367 decoded->aoc_s_entries[idx].rate.flat.multiplier);
01368 break;
01369 case AST_AOC_RATE_TYPE_VOLUME:
01370 strcat(prefix, "/");
01371 strcat(prefix, rate_str);
01372 ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
01373 decoded->aoc_s_entries[idx].rate.volume.currency_name);
01374 aoc_amount_str(msg, prefix,
01375 decoded->aoc_s_entries[idx].rate.volume.amount,
01376 decoded->aoc_s_entries[idx].rate.volume.multiplier);
01377 ast_str_append(msg, 0, "%s/Unit: %s\r\n", prefix,
01378 aoc_volume_unit_str(decoded->aoc_s_entries[idx].rate.volume.volume_unit));
01379 break;
01380 case AST_AOC_RATE_TYPE_SPECIAL_CODE:
01381 ast_str_append(msg, 0, "%s/%s: %d\r\n", prefix, rate_str,
01382 decoded->aoc_s_entries[idx].rate.special_code);
01383 break;
01384 default:
01385 break;
01386 }
01387 }
01388 }
01389
01390 static void aoc_d_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan, struct ast_str **msg)
01391 {
01392 const char *charge_str;
01393 int idx;
01394 char prefix[32];
01395
01396 if (chan) {
01397 ast_str_append(msg, 0, "Channel: %s\r\n", chan->name);
01398 ast_str_append(msg, 0, "UniqueID: %s\r\n", chan->uniqueid);
01399 }
01400
01401 charge_str = aoc_charge_type_str(decoded->charge_type);
01402 ast_str_append(msg, 0, "Type: %s\r\n", charge_str);
01403
01404 switch (decoded->charge_type) {
01405 case AST_AOC_CHARGE_CURRENCY:
01406 case AST_AOC_CHARGE_UNIT:
01407 ast_str_append(msg, 0, "BillingID: %s\r\n",
01408 aoc_billingid_str(decoded->billing_id));
01409 ast_str_append(msg, 0, "TypeOfCharging: %s\r\n",
01410 aoc_type_of_totaling_str(decoded->total_type));
01411 break;
01412 default:
01413 break;
01414 }
01415
01416 switch (decoded->charge_type) {
01417 case AST_AOC_CHARGE_CURRENCY:
01418 ast_str_append(msg, 0, "%s: %s\r\n", charge_str,
01419 decoded->currency_name);
01420 aoc_amount_str(msg, charge_str,
01421 decoded->currency_amount,
01422 decoded->multiplier);
01423 break;
01424 case AST_AOC_CHARGE_UNIT:
01425 ast_str_append(msg, 0, "%s/NumberItems: %d\r\n", charge_str,
01426 decoded->unit_count);
01427 for (idx = 0; idx < decoded->unit_count; ++idx) {
01428 snprintf(prefix, sizeof(prefix), "%s/Item(%d)", charge_str, idx);
01429 if (decoded->unit_list[idx].valid_amount) {
01430 ast_str_append(msg, 0, "%s/NumberOf: %u\r\n", prefix,
01431 decoded->unit_list[idx].amount);
01432 }
01433 if (decoded->unit_list[idx].valid_type) {
01434 ast_str_append(msg, 0, "%s/TypeOf: %u\r\n", prefix,
01435 decoded->unit_list[idx].type);
01436 }
01437 }
01438 break;
01439 default:
01440 break;
01441 }
01442 }
01443
01444 static void aoc_e_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan, struct ast_str **msg)
01445 {
01446 const char *charge_str;
01447 int idx;
01448 char prefix[32];
01449
01450 if (chan) {
01451 ast_str_append(msg, 0, "Channel: %s\r\n", chan->name);
01452 ast_str_append(msg, 0, "UniqueID: %s\r\n", chan->uniqueid);
01453 }
01454
01455 charge_str = "ChargingAssociation";
01456
01457 switch (decoded->charging_association.charging_type) {
01458 case AST_AOC_CHARGING_ASSOCIATION_NUMBER:
01459 snprintf(prefix, sizeof(prefix), "%s/Number", charge_str);
01460 ast_str_append(msg, 0, "%s: %s\r\n", prefix,
01461 decoded->charging_association.charge.number.number);
01462 ast_str_append(msg, 0, "%s/Plan: %d\r\n", prefix,
01463 decoded->charging_association.charge.number.plan);
01464 break;
01465 case AST_AOC_CHARGING_ASSOCIATION_ID:
01466 ast_str_append(msg, 0, "%s/ID: %d\r\n", charge_str, decoded->charging_association.charge.id);
01467 break;
01468 case AST_AOC_CHARGING_ASSOCIATION_NA:
01469 default:
01470 break;
01471 }
01472
01473 charge_str = aoc_charge_type_str(decoded->charge_type);
01474 ast_str_append(msg, 0, "Type: %s\r\n", charge_str);
01475 switch (decoded->charge_type) {
01476 case AST_AOC_CHARGE_CURRENCY:
01477 case AST_AOC_CHARGE_UNIT:
01478 ast_str_append(msg, 0, "BillingID: %s\r\n",
01479 aoc_billingid_str(decoded->billing_id));
01480 break;
01481 default:
01482 break;
01483 }
01484 switch (decoded->charge_type) {
01485 case AST_AOC_CHARGE_CURRENCY:
01486 ast_str_append(msg, 0, "%s: %s\r\n", charge_str,
01487 decoded->currency_name);
01488 aoc_amount_str(msg, charge_str,
01489 decoded->currency_amount,
01490 decoded->multiplier);
01491 break;
01492 case AST_AOC_CHARGE_UNIT:
01493 ast_str_append(msg, 0, "%s/NumberItems: %d\r\n", charge_str,
01494 decoded->unit_count);
01495 for (idx = 0; idx < decoded->unit_count; ++idx) {
01496 snprintf(prefix, sizeof(prefix), "%s/Item(%d)", charge_str, idx);
01497 if (decoded->unit_list[idx].valid_amount) {
01498 ast_str_append(msg, 0, "%s/NumberOf: %u\r\n", prefix,
01499 decoded->unit_list[idx].amount);
01500 }
01501 if (decoded->unit_list[idx].valid_type) {
01502 ast_str_append(msg, 0, "%s/TypeOf: %u\r\n", prefix,
01503 decoded->unit_list[idx].type);
01504 }
01505 }
01506 break;
01507 default:
01508 break;
01509 }
01510 }
01511
01512 int ast_aoc_manager_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan)
01513 {
01514 struct ast_str *msg;
01515
01516 if (!decoded || !(msg = ast_str_create(1024))) {
01517 return -1;
01518 }
01519
01520 switch (decoded->msg_type) {
01521 case AST_AOC_S:
01522 if (chan) {
01523 aoc_s_event(decoded, chan, &msg);
01524 ast_manager_event(chan, EVENT_FLAG_AOC, "AOC-S", "%s", ast_str_buffer(msg));
01525 }
01526 break;
01527 case AST_AOC_D:
01528 if (chan) {
01529 aoc_d_event(decoded, chan, &msg);
01530 ast_manager_event(chan, EVENT_FLAG_AOC, "AOC-D", "%s", ast_str_buffer(msg));
01531 }
01532 break;
01533 case AST_AOC_E:
01534 {
01535 struct ast_channel *chans[1];
01536 aoc_e_event(decoded, chan, &msg);
01537 chans[0] = chan;
01538 ast_manager_event_multichan(EVENT_FLAG_AOC, "AOC-E", chan ? 1 : 0, chans, "%s", ast_str_buffer(msg));
01539 }
01540 break;
01541 default:
01542
01543 break;
01544 }
01545
01546 ast_free(msg);
01547 return 0;
01548 }
01549
01550 int ast_aoc_decoded2str(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
01551 {
01552 if (!decoded || !msg) {
01553 return -1;
01554 }
01555
01556 switch (decoded->msg_type) {
01557 case AST_AOC_S:
01558 ast_str_append(msg, 0, "AOC-S\r\n");
01559 aoc_s_event(decoded, NULL, msg);
01560 break;
01561 case AST_AOC_D:
01562 ast_str_append(msg, 0, "AOC-D\r\n");
01563 aoc_d_event(decoded, NULL, msg);
01564 break;
01565 case AST_AOC_E:
01566 ast_str_append(msg, 0, "AOC-E\r\n");
01567 aoc_e_event(decoded, NULL, msg);
01568 break;
01569 case AST_AOC_REQUEST:
01570 ast_str_append(msg, 0, "AOC-Request\r\n");
01571 aoc_request_event(decoded, NULL, msg);
01572 break;
01573 }
01574
01575 return 0;
01576 }
01577
01578 static void aoc_display_decoded_debug(const struct ast_aoc_decoded *decoded, int decoding, struct ast_channel *chan)
01579 {
01580 struct ast_str *msg;
01581
01582 if (!decoded || !(msg = ast_str_create(1024))) {
01583 return;
01584 }
01585
01586 if (decoding) {
01587 ast_str_append(&msg, 0, "---- DECODED AOC MSG ----\r\n");
01588 } else {
01589 ast_str_append(&msg, 0, "---- ENCODED AOC MSG ----\r\n");
01590 }
01591 if (chan) {
01592 ast_str_append(&msg, 0, "CHANNEL: %s\r\n", chan->name);
01593 }
01594
01595 if (ast_aoc_decoded2str(decoded, &msg)) {
01596 ast_free(msg);
01597 return;
01598 }
01599
01600 ast_verb(1, "%s\r\n", ast_str_buffer(msg));
01601 ast_free(msg);
01602 }
01603
01604 static struct ast_cli_entry aoc_cli[] = {
01605 AST_CLI_DEFINE(aoc_cli_debug_enable, "enable cli debugging of AOC messages"),
01606 };
01607
01608 static void aoc_shutdown(void)
01609 {
01610 ast_cli_unregister_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
01611 }
01612 int ast_aoc_cli_init(void)
01613 {
01614 ast_register_atexit(aoc_shutdown);
01615 return ast_cli_register_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
01616 }