Wed Apr 6 11:29:37 2011

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 #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 /* Encoded Payload Flags */
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 /* AOC Payload Header. Holds all the encoded AOC data to pass on the wire */
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 /* Decoded AOC data */
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    /* currency information */
00077    enum ast_aoc_currency_multiplier multiplier;
00078    unsigned int currency_amount;
00079    char currency_name[AOC_CURRENCY_NAME_SIZE];
00080 
00081    /* unit information */
00082    int unit_count;
00083    struct ast_aoc_unit_entry unit_list[32];
00084 
00085    /* Billing Id */
00086    enum ast_aoc_billing_id billing_id;
00087 
00088    /* Charging Association information */
00089    struct ast_aoc_charging_association charging_association;
00090 
00091    /* AOC-S charge information */
00092    int aoc_s_count;
00093    struct ast_aoc_s_entry aoc_s_entries[10];
00094 
00095    /* Is this an AOC Termination Request */
00096    char termination_request;
00097 };
00098 
00099 /*! \brief AOC Payload Information Elements */
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 /*! \brief AOC IE payload header */
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    /* verify input */
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; /* only one byte */
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; /* only one byte */
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; /* only one byte */
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             /* everything in the charging_association struct is a single byte except for the id */
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    /* verify our encoded payload is actually large enough to hold all the ies */
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    /* decode flags */
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    /* decode information elements */
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  * \internal
00384  * \brief append an AOC information element
00385  * \note data is expected to already be in network byte order at this point
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; /* only one byte */
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, /* only one byte */
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; /* only one byte */
00472          ie.amount = htonl(decoded->unit_list[i].amount);
00473          ie.valid_type = decoded->unit_list[i].valid_type; /* only one byte */
00474          ie.type = decoded->unit_list[i].type; /* only one byte */
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; /* only one byte */
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;   /* only one byte */
00489       if (decoded->charging_association.charging_type == AST_AOC_CHARGING_ASSOCIATION_NUMBER) {
00490          ie.ca.charge.number.plan = decoded->charging_association.charge.number.plan; /* only one byte */
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    /* create information element buffer before allocating the payload,
00528     * by doing this the exact size of the payload + the id data can be
00529     * allocated all at once. */
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    /* -- Set ie data buffer */
00540    if (ied.pos) {
00541       /* this is safe because encoded was allocated to fit this perfectly */
00542       memcpy(encoded->data, ied.buf, ied.pos);
00543       encoded->datalen = htons(ied.pos);
00544    }
00545 
00546    /* --- Set Flags --- */
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    /* if it is type request, set the types requested, else set charge type */
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    /* --- Set Version Number --- */
00596    encoded->version = AST_AOC_ENCODE_VERSION;
00597 
00598    /* set the output size  */
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  * \internal
00951  * \brief Convert AST_AOC_VOLUME_UNIT to string.
00952  * \since 1.8
00953  *
00954  * \param value Value to convert to string.
00955  *
00956  * \return String equivalent.
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  * \internal
00979  * \brief Convert ast_aoc_charged_item to string.
00980  * \since 1.8
00981  *
00982  * \param value Value to convert to string.
00983  *
00984  * \return String equivalent.
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  * \internal
01019  * \brief Convert ast_aoc_total_type to string.
01020  * \since 1.8
01021  *
01022  * \param value Value to convert to string.
01023  *
01024  * \return String equivalent.
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  * \internal
01044  * \brief Convert ast_aoc_rate_type to string.
01045  * \since 1.8
01046  *
01047  * \param value Value to convert to string.
01048  *
01049  * \return String equivalent.
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  * \internal
01084  * \brief Convert AST_AOC_TIME_SCALE to string.
01085  * \since 1.8
01086  *
01087  * \param value Value to convert to string.
01088  *
01089  * \return String equivalent.
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  * \internal
01249  * \brief Append the time structure to the event message string.
01250  * \since 1.8
01251  *
01252  * \param msg Event message string being built.
01253  * \param prefix Prefix to add to the amount lines.
01254  * \param name Name of the time structure to convert.
01255  * \param time Data to convert.
01256  * \param scale Data to convert.
01257  *
01258  * \return Nothing
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  * \internal
01269  * \brief Append the amount structure to the event message string.
01270  * \since 1.8
01271  *
01272  * \param msg Event message string being built.
01273  * \param prefix Prefix to add to the amount lines.
01274  * \param amount Data to convert.
01275  * \param multipler to convert
01276  *
01277  * \return Nothing
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       /* events for AST_AOC_REQUEST are not generated here */
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 }

Generated on Wed Apr 6 11:29:37 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7