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