Mon Aug 31 12:29:57 2015

Asterisk developer's documentation


aoc.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2010, Digium, Inc.
00005  *
00006  * David Vossel <dvossel@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*!
00020  * \file
00021  * \brief generic AOC payload generation encoding and decoding
00022  *
00023  * \author David Vossel <dvossel@digium.com>
00024  */
00025 
00026 /*** MODULEINFO
00027    <support_level>core</support_level>
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 /* Encoded Payload Flags */
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 /* AOC Payload Header. Holds all the encoded AOC data to pass on the wire */
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 /* Decoded AOC data */
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    /* currency information */
00081    enum ast_aoc_currency_multiplier multiplier;
00082    unsigned int currency_amount;
00083    char currency_name[AOC_CURRENCY_NAME_SIZE];
00084 
00085    /* unit information */
00086    int unit_count;
00087    struct ast_aoc_unit_entry unit_list[32];
00088 
00089    /* Billing Id */
00090    enum ast_aoc_billing_id billing_id;
00091 
00092    /* Charging Association information */
00093    struct ast_aoc_charging_association charging_association;
00094 
00095    /* AOC-S charge information */
00096    int aoc_s_count;
00097    struct ast_aoc_s_entry aoc_s_entries[10];
00098 
00099    /* Is this an AOC Termination Request */
00100    char termination_request;
00101 };
00102 
00103 /*! \brief AOC Payload Information Elements */
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 /*! \brief AOC IE payload header */
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    /* verify input */
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; /* only one byte */
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; /* only one byte */
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; /* only one byte */
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             /* everything in the charging_association struct is a single byte except for the id */
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    /* verify our encoded payload is actually large enough to hold all the ies */
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    /* decode flags */
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    /* decode information elements */
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  * \internal
00388  * \brief append an AOC information element
00389  * \note data is expected to already be in network byte order at this point
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; /* only one byte */
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, /* only one byte */
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; /* only one byte */
00476          ie.amount = htonl(decoded->unit_list[i].amount);
00477          ie.valid_type = decoded->unit_list[i].valid_type; /* only one byte */
00478          ie.type = decoded->unit_list[i].type; /* only one byte */
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; /* only one byte */
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;   /* only one byte */
00493       if (decoded->charging_association.charging_type == AST_AOC_CHARGING_ASSOCIATION_NUMBER) {
00494          ie.ca.charge.number.plan = decoded->charging_association.charge.number.plan; /* only one byte */
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    /* create information element buffer before allocating the payload,
00532     * by doing this the exact size of the payload + the id data can be
00533     * allocated all at once. */
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    /* -- Set ie data buffer */
00544    if (ied.pos) {
00545       /* this is safe because encoded was allocated to fit this perfectly */
00546       memcpy(encoded->data, ied.buf, ied.pos);
00547       encoded->datalen = htons(ied.pos);
00548    }
00549 
00550    /* --- Set Flags --- */
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    /* if it is type request, set the types requested, else set charge type */
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    /* --- Set Version Number --- */
00600    encoded->version = AST_AOC_ENCODE_VERSION;
00601 
00602    /* set the output size  */
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  * \internal
00955  * \brief Convert AST_AOC_VOLUME_UNIT to string.
00956  * \since 1.8
00957  *
00958  * \param value Value to convert to string.
00959  *
00960  * \return String equivalent.
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  * \internal
00983  * \brief Convert ast_aoc_charged_item to string.
00984  * \since 1.8
00985  *
00986  * \param value Value to convert to string.
00987  *
00988  * \return String equivalent.
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  * \internal
01023  * \brief Convert ast_aoc_total_type to string.
01024  * \since 1.8
01025  *
01026  * \param value Value to convert to string.
01027  *
01028  * \return String equivalent.
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  * \internal
01048  * \brief Convert ast_aoc_rate_type to string.
01049  * \since 1.8
01050  *
01051  * \param value Value to convert to string.
01052  *
01053  * \return String equivalent.
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  * \internal
01088  * \brief Convert AST_AOC_TIME_SCALE to string.
01089  * \since 1.8
01090  *
01091  * \param value Value to convert to string.
01092  *
01093  * \return String equivalent.
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  * \internal
01253  * \brief Append the time structure to the event message string.
01254  * \since 1.8
01255  *
01256  * \param msg Event message string being built.
01257  * \param prefix Prefix to add to the amount lines.
01258  * \param name Name of the time structure to convert.
01259  * \param time Data to convert.
01260  * \param scale Data to convert.
01261  *
01262  * \return Nothing
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  * \internal
01273  * \brief Append the amount structure to the event message string.
01274  * \since 1.8
01275  *
01276  * \param msg Event message string being built.
01277  * \param prefix Prefix to add to the amount lines.
01278  * \param amount Data to convert.
01279  * \param multipler to convert
01280  *
01281  * \return Nothing
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       /* events for AST_AOC_REQUEST are not generated here */
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 }

Generated on 31 Aug 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1