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: 433498 $");
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 #include "asterisk/stasis_channels.h"
00040 #include "asterisk/stasis_message_router.h"
00041 
00042 /*** DOCUMENTATION
00043    <managerEvent language="en_US" name="AOC-S">
00044       <managerEventInstance class="EVENT_FLAG_AOC">
00045          <synopsis>Raised when an Advice of Charge message is sent at the beginning of a call.</synopsis>
00046          <syntax>
00047             <channel_snapshot/>
00048             <parameter name="Chargeable" />
00049             <parameter name="RateType">
00050                <enumlist>
00051                   <enum name="NotAvailable" />
00052                   <enum name="Free" />
00053                   <enum name="FreeFromBeginning" />
00054                   <enum name="Duration" />
00055                   <enum name="Flag" />
00056                   <enum name="Volume" />
00057                   <enum name="SpecialCode" />
00058                </enumlist>
00059             </parameter>
00060             <parameter name="Currency" />
00061             <parameter name="Name" />
00062             <parameter name="Cost" />
00063             <parameter name="Multiplier">
00064                <enumlist>
00065                   <enum name="1/1000" />
00066                   <enum name="1/100" />
00067                   <enum name="1/10" />
00068                   <enum name="1" />
00069                   <enum name="10" />
00070                   <enum name="100" />
00071                   <enum name="1000" />
00072                </enumlist>
00073             </parameter>
00074             <parameter name="ChargingType" />
00075             <parameter name="StepFunction" />
00076             <parameter name="Granularity" />
00077             <parameter name="Length" />
00078             <parameter name="Scale" />
00079             <parameter name="Unit">
00080                <enumlist>
00081                   <enum name="Octect" />
00082                   <enum name="Segment" />
00083                   <enum name="Message" />
00084                </enumlist>
00085             </parameter>
00086             <parameter name="SpecialCode" />
00087          </syntax>
00088       </managerEventInstance>
00089    </managerEvent>
00090    <managerEvent language="en_US" name="AOC-D">
00091       <managerEventInstance class="EVENT_FLAG_AOC">
00092          <synopsis>Raised when an Advice of Charge message is sent during a call.</synopsis>
00093          <syntax>
00094             <channel_snapshot/>
00095             <parameter name="Charge" />
00096             <parameter name="Type">
00097                <enumlist>
00098                   <enum name="NotAvailable" />
00099                   <enum name="Free" />
00100                   <enum name="Currency" />
00101                   <enum name="Units" />
00102                </enumlist>
00103             </parameter>
00104             <parameter name="BillingID">
00105                <enumlist>
00106                   <enum name="Normal" />
00107                   <enum name="Reverse" />
00108                   <enum name="CreditCard" />
00109                   <enum name="CallForwardingUnconditional" />
00110                   <enum name="CallForwardingBusy" />
00111                   <enum name="CallForwardingNoReply" />
00112                   <enum name="CallDeflection" />
00113                   <enum name="CallTransfer" />
00114                   <enum name="NotAvailable" />
00115                </enumlist>
00116             </parameter>
00117             <parameter name="TotalType">
00118                <enumlist>
00119                   <enum name="SubTotal" />
00120                   <enum name="Total" />
00121                </enumlist>
00122             </parameter>
00123             <parameter name="Currency" />
00124             <parameter name="Name" />
00125             <parameter name="Cost" />
00126             <parameter name="Multiplier">
00127                <enumlist>
00128                   <enum name="1/1000" />
00129                   <enum name="1/100" />
00130                   <enum name="1/10" />
00131                   <enum name="1" />
00132                   <enum name="10" />
00133                   <enum name="100" />
00134                   <enum name="1000" />
00135                </enumlist>
00136             </parameter>
00137             <parameter name="Units" />
00138             <parameter name="NumberOf" />
00139             <parameter name="TypeOf" />
00140          </syntax>
00141       </managerEventInstance>
00142    </managerEvent>
00143    <managerEvent language="en_US" name="AOC-E">
00144       <managerEventInstance class="EVENT_FLAG_AOC">
00145          <synopsis>Raised when an Advice of Charge message is sent at the end of a call.</synopsis>
00146          <syntax>
00147             <channel_snapshot/>
00148             <parameter name="ChargingAssociation" />
00149             <parameter name="Number" />
00150             <parameter name="Plan" />
00151             <parameter name="ID" />
00152             <xi:include xpointer="xpointer(/docs/managerEvent[@name='AOC-D']/managerEventInstance/syntax/parameter)" />
00153          </syntax>
00154       </managerEventInstance>
00155    </managerEvent>
00156 ***/
00157 
00158 /* Encoded Payload Flags */
00159 #define AST_AOC_ENCODED_TYPE_REQUEST    (0 << 0)
00160 #define AST_AOC_ENCODED_TYPE_D          (1 << 0)
00161 #define AST_AOC_ENCODED_TYPE_E          (2 << 0)
00162 #define AST_AOC_ENCODED_TYPE_S          (3 << 0)
00163 
00164 #define AST_AOC_ENCODED_REQUEST_S       (1 << 2)
00165 #define AST_AOC_ENCODED_REQUEST_D       (1 << 3)
00166 #define AST_AOC_ENCODED_REQUEST_E       (1 << 4)
00167 
00168 #define AST_AOC_ENCODED_CHARGE_NA       (0 << 5)
00169 #define AST_AOC_ENCODED_CHARGE_FREE     (1 << 5)
00170 #define AST_AOC_ENCODED_CHARGE_CURRENCY (2 << 5)
00171 #define AST_AOC_ENCODED_CHARGE_UNIT     (3 << 5)
00172 
00173 #define AST_AOC_ENCODED_CHARGE_SUBTOTAL (1 << 7)
00174 #define AST_AOC_ENCODED_CHARGE_TOTAL    (0 << 7)
00175 
00176 #define AST_AOC_ENCODE_VERSION 1
00177 
00178 
00179 static char aoc_debug_enabled = 0;
00180 static void aoc_display_decoded_debug(const struct ast_aoc_decoded *decoded, int decoding, struct ast_channel *chan);
00181 static int aoc_s_add_entry(struct ast_aoc_decoded *decoded, struct ast_aoc_s_entry *entry);
00182 
00183 /* AOC Payload Header. Holds all the encoded AOC data to pass on the wire */
00184 struct ast_aoc_encoded {
00185    uint8_t  version;
00186    uint8_t  flags;
00187    uint16_t datalen;
00188    unsigned char data[0];
00189 };
00190 
00191 /* Decoded AOC data */
00192 struct ast_aoc_decoded {
00193    enum ast_aoc_type msg_type;
00194    enum ast_aoc_charge_type charge_type;
00195    enum ast_aoc_request request_flag;
00196    enum ast_aoc_total_type total_type;
00197 
00198    /* currency information */
00199    enum ast_aoc_currency_multiplier multiplier;
00200    unsigned int currency_amount;
00201    char currency_name[AOC_CURRENCY_NAME_SIZE];
00202 
00203    /* unit information */
00204    int unit_count;
00205    struct ast_aoc_unit_entry unit_list[32];
00206 
00207    /* Billing Id */
00208    enum ast_aoc_billing_id billing_id;
00209 
00210    /* Charging Association information */
00211    struct ast_aoc_charging_association charging_association;
00212 
00213    /* AOC-S charge information */
00214    int aoc_s_count;
00215    struct ast_aoc_s_entry aoc_s_entries[10];
00216 
00217    /* Is this an AOC Termination Request */
00218    char termination_request;
00219 };
00220 
00221 /*! \brief AOC Payload Information Elements */
00222 enum AOC_IE {
00223    AOC_IE_CURRENCY = 1,
00224    AOC_IE_UNIT = 2,
00225    AOC_IE_BILLING = 3,
00226    AOC_IE_CHARGING_ASSOCIATION = 4,
00227    AOC_IE_RATE = 5,
00228    AOC_IE_TERMINATION_REQUEST = 6,
00229 };
00230 
00231 /*! \brief AOC IE payload header */
00232 struct aoc_pl_ie_hdr {
00233    uint8_t ie_id;
00234    uint8_t datalen;
00235    char data[0];
00236 } __attribute__((packed));
00237 
00238 struct aoc_ie_currency {
00239    uint32_t amount;
00240    uint8_t  multiplier;
00241    char name[AOC_CURRENCY_NAME_SIZE];
00242 } __attribute__((packed));
00243 
00244 struct aoc_ie_unit {
00245    uint32_t amount;
00246    uint8_t valid_type;
00247    uint8_t valid_amount;
00248    uint8_t type;
00249 } __attribute__((packed));
00250 
00251 struct aoc_ie_billing {
00252    uint8_t id;
00253 } __attribute__((packed));
00254 
00255 struct aoc_ie_charging_association {
00256    struct ast_aoc_charging_association ca;
00257 } __attribute__((packed));
00258 
00259 struct aoc_ie_charging_rate {
00260    struct ast_aoc_s_entry entry;
00261 } __attribute__((packed));
00262 
00263 struct ast_aoc_decoded *ast_aoc_create(const enum ast_aoc_type msg_type,
00264       const enum ast_aoc_charge_type charge_type,
00265       const enum ast_aoc_request requests)
00266 {
00267    struct ast_aoc_decoded *decoded = NULL;
00268 
00269    /* verify input */
00270    if (((unsigned int) charge_type > AST_AOC_CHARGE_UNIT) ||
00271       ((unsigned int) msg_type > AST_AOC_E) ||
00272       ((msg_type == AST_AOC_REQUEST) && !requests)) {
00273 
00274       ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object, invalid input\n");
00275       return NULL;
00276    }
00277 
00278    if (!(decoded = ast_calloc(1, sizeof(struct ast_aoc_decoded)))) {
00279       ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object \n");
00280       return NULL;
00281    }
00282 
00283    decoded->msg_type = msg_type;
00284 
00285    if (msg_type == AST_AOC_REQUEST) {
00286       decoded->request_flag = requests;
00287    } else if ((msg_type == AST_AOC_D) || (msg_type == AST_AOC_E)) {
00288       decoded->charge_type = charge_type;
00289    }
00290 
00291    return decoded;
00292 }
00293 
00294 void *ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
00295 {
00296    ast_free(decoded);
00297    return NULL;
00298 }
00299 
00300 void *ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
00301 {
00302    ast_free(encoded);
00303    return NULL;
00304 }
00305 
00306 static void aoc_parse_ie_charging_rate(struct ast_aoc_decoded *decoded, const struct aoc_ie_charging_rate *ie)
00307 {
00308    struct ast_aoc_s_entry entry = { 0, };
00309 
00310    entry.charged_item = ntohs(ie->entry.charged_item);
00311    entry.rate_type = ntohs(ie->entry.rate_type);
00312 
00313    switch (entry.rate_type) {
00314    case AST_AOC_RATE_TYPE_DURATION:
00315       entry.rate.duration.multiplier = ntohs(ie->entry.rate.duration.multiplier);
00316       entry.rate.duration.amount = ntohl(ie->entry.rate.duration.amount);
00317       entry.rate.duration.time = ntohl(ie->entry.rate.duration.time);
00318       entry.rate.duration.time_scale = ntohs(ie->entry.rate.duration.time_scale);
00319       entry.rate.duration.granularity_time = ntohl(ie->entry.rate.duration.granularity_time);
00320       entry.rate.duration.granularity_time_scale = ntohs(ie->entry.rate.duration.granularity_time_scale);
00321       entry.rate.duration.charging_type = ie->entry.rate.duration.charging_type; /* only one byte */
00322 
00323       if (!ast_strlen_zero(ie->entry.rate.duration.currency_name)) {
00324          ast_copy_string(entry.rate.duration.currency_name,
00325             ie->entry.rate.duration.currency_name,
00326             sizeof(entry.rate.duration.currency_name));
00327       }
00328       break;
00329    case AST_AOC_RATE_TYPE_FLAT:
00330       entry.rate.flat.multiplier = ntohs(ie->entry.rate.flat.multiplier);
00331       entry.rate.flat.amount = ntohl(ie->entry.rate.flat.amount);
00332       if (!ast_strlen_zero(ie->entry.rate.flat.currency_name)) {
00333          ast_copy_string(entry.rate.flat.currency_name,
00334             ie->entry.rate.flat.currency_name,
00335             sizeof(entry.rate.flat.currency_name));
00336       }
00337       break;
00338    case AST_AOC_RATE_TYPE_VOLUME:
00339       entry.rate.volume.multiplier = ntohs(ie->entry.rate.volume.multiplier);
00340       entry.rate.volume.amount = ntohl(ie->entry.rate.volume.amount);
00341       entry.rate.volume.volume_unit = ntohs(ie->entry.rate.volume.volume_unit);
00342       if (!ast_strlen_zero(ie->entry.rate.volume.currency_name)) {
00343          ast_copy_string(entry.rate.volume.currency_name,
00344             ie->entry.rate.volume.currency_name,
00345             sizeof(entry.rate.volume.currency_name));
00346       }
00347       break;
00348    case AST_AOC_RATE_TYPE_SPECIAL_CODE:
00349       entry.rate.special_code = ntohs(ie->entry.rate.special_code);
00350       break;
00351    }
00352 
00353    aoc_s_add_entry(decoded, &entry);
00354 }
00355 
00356 static int aoc_parse_ie(struct ast_aoc_decoded *decoded, unsigned char *data, unsigned int datalen)
00357 {
00358    enum AOC_IE ie_id;
00359    unsigned int len;
00360 
00361    while (datalen >= 2) {
00362       ie_id = data[0];
00363       len = data[1];
00364       if (len > datalen -2) {
00365          ast_log(LOG_ERROR, "AOC information element length exceeds the total message size\n");
00366          return -1;
00367       }
00368 
00369       switch(ie_id) {
00370       case AOC_IE_CURRENCY:
00371          if (len == sizeof(struct aoc_ie_currency)) {
00372             struct aoc_ie_currency ie;
00373             memcpy(&ie, data + 2, len);
00374             decoded->currency_amount = ntohl(ie.amount);
00375             decoded->multiplier = ie.multiplier; /* only one byte */
00376             memcpy(decoded->currency_name, ie.name, sizeof(decoded->currency_name));
00377          } else {
00378             ast_log(LOG_WARNING, "Received invalid currency ie\n");
00379          }
00380          break;
00381       case AOC_IE_UNIT:
00382          if (len == sizeof(struct aoc_ie_unit)) {
00383             struct aoc_ie_unit ie;
00384             memcpy(&ie, data + 2, len);
00385             ast_aoc_add_unit_entry(decoded, ie.valid_amount, ntohl(ie.amount), ie.valid_type, ie.type);
00386          } else {
00387             ast_log(LOG_WARNING, "Received invalid unit ie\n");
00388          }
00389          break;
00390       case AOC_IE_BILLING:
00391          if (len == sizeof(struct aoc_ie_billing)) {
00392             struct aoc_ie_billing ie;
00393             memcpy(&ie, data + 2, len);
00394             decoded->billing_id = ie.id; /* only one byte */
00395          } else {
00396             ast_log(LOG_WARNING, "Received invalid billing ie\n");
00397          }
00398          break;
00399       case AOC_IE_CHARGING_ASSOCIATION:
00400          if (len == sizeof(struct aoc_ie_charging_association)) {
00401             memcpy(&decoded->charging_association, data + 2, sizeof(decoded->charging_association));
00402             /* everything in the charging_association struct is a single byte except for the id */
00403             if (decoded->charging_association.charging_type == AST_AOC_CHARGING_ASSOCIATION_ID) {
00404                decoded->charging_association.charge.id = ntohl(decoded->charging_association.charge.id);
00405             }
00406          } else {
00407             ast_log(LOG_WARNING, "Received invalid charging association ie\n");
00408          }
00409          break;
00410       case AOC_IE_RATE:
00411          if (len == sizeof(struct aoc_ie_charging_rate)) {
00412             struct aoc_ie_charging_rate ie;
00413             memcpy(&ie, data + 2, len);
00414             aoc_parse_ie_charging_rate(decoded, &ie);
00415          } else {
00416             ast_log(LOG_WARNING, "Received invalid charging rate ie\n");
00417          }
00418          break;
00419       case AOC_IE_TERMINATION_REQUEST:
00420          if (len == 0) {
00421             decoded->termination_request = 1;
00422          } else {
00423             ast_log(LOG_WARNING, "Received invalid termination request ie\n");
00424          }
00425          break;
00426       default:
00427          ast_log(LOG_WARNING, "Unknown AOC Information Element, ignoring.\n");
00428       }
00429 
00430       datalen -= (len + 2);
00431       data += (len + 2);
00432    }
00433    return 0;
00434 }
00435 
00436 struct ast_aoc_decoded *ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan)
00437 {
00438    struct ast_aoc_decoded *decoded;
00439 
00440    /* verify our encoded payload is actually large enough to hold all the ies */
00441    if ((size - (sizeof(struct ast_aoc_encoded)) != ntohs(encoded->datalen))) {
00442       ast_log(LOG_WARNING, "Corrupted aoc encoded object, can not decode\n");
00443       return NULL;
00444    }
00445 
00446    if (!(decoded = ast_calloc(1, sizeof(struct ast_aoc_decoded)))) {
00447       ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object \n");
00448       return NULL;
00449    }
00450 
00451    /* decode flags */
00452 
00453    if ((encoded->flags & AST_AOC_ENCODED_TYPE_S) == AST_AOC_ENCODED_TYPE_S) {
00454       decoded->msg_type = AST_AOC_S;
00455    } else if (encoded->flags & AST_AOC_ENCODED_TYPE_E) {
00456       decoded->msg_type = AST_AOC_E;
00457    } else if (encoded->flags & AST_AOC_ENCODED_TYPE_D) {
00458       decoded->msg_type = AST_AOC_D;
00459    } else {
00460       decoded->msg_type = AST_AOC_REQUEST;
00461    }
00462 
00463    if (decoded->msg_type == AST_AOC_REQUEST) {
00464       if (encoded->flags & AST_AOC_ENCODED_REQUEST_S) {
00465          decoded->request_flag |= AST_AOC_REQUEST_S;
00466       }
00467       if (encoded->flags & AST_AOC_ENCODED_REQUEST_D) {
00468          decoded->request_flag |= AST_AOC_REQUEST_D;
00469       }
00470       if (encoded->flags & AST_AOC_ENCODED_REQUEST_E) {
00471          decoded->request_flag |= AST_AOC_REQUEST_E;
00472       }
00473    } else if ((decoded->msg_type == AST_AOC_D) || (decoded->msg_type == AST_AOC_E)) {
00474       if ((encoded->flags & AST_AOC_ENCODED_CHARGE_UNIT) == AST_AOC_ENCODED_CHARGE_UNIT) {
00475          decoded->charge_type = AST_AOC_CHARGE_UNIT;
00476       } else if ((encoded->flags & AST_AOC_ENCODED_CHARGE_CURRENCY) == AST_AOC_ENCODED_CHARGE_CURRENCY) {
00477          decoded->charge_type = AST_AOC_CHARGE_CURRENCY;
00478       } else if ((encoded->flags & AST_AOC_ENCODED_CHARGE_FREE) == AST_AOC_ENCODED_CHARGE_FREE) {
00479          decoded->charge_type = AST_AOC_CHARGE_FREE;
00480       } else {
00481          decoded->charge_type = AST_AOC_CHARGE_NA;
00482       }
00483 
00484       if (encoded->flags & AST_AOC_ENCODED_CHARGE_SUBTOTAL) {
00485          decoded->total_type = AST_AOC_SUBTOTAL;
00486       }
00487    }
00488 
00489    /* decode information elements */
00490    aoc_parse_ie(decoded, encoded->data, ntohs(encoded->datalen));
00491 
00492    if (aoc_debug_enabled) {
00493       aoc_display_decoded_debug(decoded, 1, chan);
00494    }
00495 
00496    return decoded;
00497 }
00498 
00499 struct aoc_ie_data {
00500    unsigned char buf[1024];
00501    int pos;
00502 };
00503 
00504 /*!
00505  * \internal
00506  * \brief append an AOC information element
00507  * \note data is expected to already be in network byte order at this point
00508  */
00509 static int aoc_append_ie(struct aoc_ie_data *ied, unsigned short ie_id, const void *data, unsigned short datalen)
00510 {
00511    if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
00512       ast_log(LOG_WARNING, "Failure to append AOC information element, out of space \n");
00513       return -1;
00514    }
00515    ied->buf[ied->pos++] = ie_id;
00516    ied->buf[ied->pos++] = datalen;
00517    if (datalen) {
00518       memcpy(ied->buf + ied->pos, data, datalen);
00519       ied->pos += datalen;
00520    }
00521    return 0;
00522 }
00523 
00524 static void aoc_create_ie_data_charging_rate(const struct ast_aoc_s_entry *entry, struct aoc_ie_charging_rate *ie)
00525 {
00526    ie->entry.charged_item = htons(entry->charged_item);
00527    ie->entry.rate_type = htons(entry->rate_type);
00528 
00529    switch (entry->rate_type) {
00530    case AST_AOC_RATE_TYPE_DURATION:
00531       ie->entry.rate.duration.multiplier = htons(entry->rate.duration.multiplier);
00532       ie->entry.rate.duration.amount = htonl(entry->rate.duration.amount);
00533       ie->entry.rate.duration.time = htonl(entry->rate.duration.time);
00534       ie->entry.rate.duration.time_scale = htons(entry->rate.duration.time_scale);
00535       ie->entry.rate.duration.granularity_time = htonl(entry->rate.duration.granularity_time);
00536       ie->entry.rate.duration.granularity_time_scale = htons(entry->rate.duration.granularity_time_scale);
00537       ie->entry.rate.duration.charging_type = entry->rate.duration.charging_type; /* only one byte */
00538 
00539       if (!ast_strlen_zero(entry->rate.duration.currency_name)) {
00540          ast_copy_string(ie->entry.rate.duration.currency_name,
00541             entry->rate.duration.currency_name,
00542             sizeof(ie->entry.rate.duration.currency_name));
00543       }
00544       break;
00545    case AST_AOC_RATE_TYPE_FLAT:
00546       ie->entry.rate.flat.multiplier = htons(entry->rate.flat.multiplier);
00547       ie->entry.rate.flat.amount = htonl(entry->rate.flat.amount);
00548       if (!ast_strlen_zero(entry->rate.flat.currency_name)) {
00549          ast_copy_string(ie->entry.rate.flat.currency_name,
00550             entry->rate.flat.currency_name,
00551             sizeof(ie->entry.rate.flat.currency_name));
00552       }
00553       break;
00554    case AST_AOC_RATE_TYPE_VOLUME:
00555       ie->entry.rate.volume.multiplier = htons(entry->rate.volume.multiplier);
00556       ie->entry.rate.volume.amount = htonl(entry->rate.volume.amount);
00557       ie->entry.rate.volume.volume_unit = htons(entry->rate.volume.volume_unit);
00558       if (!ast_strlen_zero(entry->rate.volume.currency_name)) {
00559          ast_copy_string(ie->entry.rate.volume.currency_name,
00560             entry->rate.volume.currency_name,
00561             sizeof(ie->entry.rate.volume.currency_name));
00562       }
00563       break;
00564    case AST_AOC_RATE_TYPE_SPECIAL_CODE:
00565       ie->entry.rate.special_code = htons(entry->rate.special_code);
00566       break;
00567    }
00568 
00569 }
00570 static void aoc_create_ie_data(struct ast_aoc_decoded *decoded, struct aoc_ie_data *ied)
00571 {
00572    ied->pos = 0;
00573 
00574    if (decoded->currency_amount) {
00575       struct aoc_ie_currency ie = {
00576          .amount = htonl(decoded->currency_amount),
00577          .multiplier = decoded->multiplier, /* only one byte */
00578          .name = { 0, },
00579       };
00580 
00581       if (!ast_strlen_zero(decoded->currency_name)) {
00582          ast_copy_string(ie.name, decoded->currency_name, sizeof(ie.name));
00583       }
00584 
00585       aoc_append_ie(ied, AOC_IE_CURRENCY, (const void *) &ie, sizeof(ie));
00586    }
00587 
00588    if (decoded->unit_count) {
00589       struct aoc_ie_unit ie = { 0 };
00590       int i;
00591 
00592       for (i = 0; i < decoded->unit_count; i++) {
00593          ie.valid_amount = decoded->unit_list[i].valid_amount; /* only one byte */
00594          ie.amount = htonl(decoded->unit_list[i].amount);
00595          ie.valid_type = decoded->unit_list[i].valid_type; /* only one byte */
00596          ie.type = decoded->unit_list[i].type; /* only one byte */
00597          aoc_append_ie(ied, AOC_IE_UNIT, (const void *) &ie, sizeof(ie));
00598       }
00599    }
00600 
00601    if (decoded->billing_id) {
00602       struct aoc_ie_billing ie;
00603       ie.id = decoded->billing_id; /* only one byte */
00604       aoc_append_ie(ied, AOC_IE_BILLING, (const void *) &ie, sizeof(ie));
00605    }
00606 
00607    if (decoded->charging_association.charging_type != AST_AOC_CHARGING_ASSOCIATION_NA) {
00608       struct aoc_ie_charging_association ie;
00609       memset(&ie, 0, sizeof(ie));
00610       ie.ca.charging_type = decoded->charging_association.charging_type;   /* only one byte */
00611       if (decoded->charging_association.charging_type == AST_AOC_CHARGING_ASSOCIATION_NUMBER) {
00612          ie.ca.charge.number.plan = decoded->charging_association.charge.number.plan; /* only one byte */
00613          ast_copy_string(ie.ca.charge.number.number,
00614             decoded->charging_association.charge.number.number,
00615             sizeof(ie.ca.charge.number.number));
00616       } else if (decoded->charging_association.charging_type == AST_AOC_CHARGING_ASSOCIATION_ID) {
00617          ie.ca.charge.id = htonl(decoded->charging_association.charge.id);
00618       }
00619       aoc_append_ie(ied, AOC_IE_CHARGING_ASSOCIATION, (const void *) &ie, sizeof(ie));
00620    }
00621 
00622    if (decoded->aoc_s_count) {
00623       struct aoc_ie_charging_rate ie;
00624       int i;
00625       for (i = 0; i < decoded->aoc_s_count; i++) {
00626          memset(&ie, 0, sizeof(ie));
00627          aoc_create_ie_data_charging_rate(&decoded->aoc_s_entries[i], &ie);
00628          aoc_append_ie(ied, AOC_IE_RATE, (const void *) &ie, sizeof(ie));
00629       }
00630    }
00631 
00632    if (decoded->termination_request) {
00633       aoc_append_ie(ied, AOC_IE_TERMINATION_REQUEST, NULL, 0);
00634    }
00635 }
00636 
00637 struct ast_aoc_encoded *ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan)
00638 {
00639    struct aoc_ie_data ied;
00640    struct ast_aoc_encoded *encoded = NULL;
00641    size_t size = 0;
00642 
00643    if (!decoded || !out_size) {
00644       return NULL;
00645    }
00646 
00647    *out_size = 0;
00648 
00649    /* create information element buffer before allocating the payload,
00650     * by doing this the exact size of the payload + the id data can be
00651     * allocated all at once. */
00652    aoc_create_ie_data(decoded, &ied);
00653 
00654    size = sizeof(struct ast_aoc_encoded) + ied.pos;
00655 
00656    if (!(encoded = ast_calloc(1, size))) {
00657       ast_log(LOG_WARNING, "Failed to create ast_aoc_encoded object during decode routine. \n");
00658       return NULL;
00659    }
00660 
00661    /* -- Set ie data buffer */
00662    if (ied.pos) {
00663       /* this is safe because encoded was allocated to fit this perfectly */
00664       memcpy(encoded->data, ied.buf, ied.pos);
00665       encoded->datalen = htons(ied.pos);
00666    }
00667 
00668    /* --- Set Flags --- */
00669    switch (decoded->msg_type) {
00670    case AST_AOC_S:
00671       encoded->flags = AST_AOC_ENCODED_TYPE_S;
00672       break;
00673    case AST_AOC_D:
00674       encoded->flags = AST_AOC_ENCODED_TYPE_D;
00675       break;
00676    case AST_AOC_E:
00677       encoded->flags = AST_AOC_ENCODED_TYPE_E;
00678       break;
00679    case AST_AOC_REQUEST:
00680       encoded->flags = AST_AOC_ENCODED_TYPE_REQUEST;
00681    default:
00682       break;
00683    }
00684 
00685    /* if it is type request, set the types requested, else set charge type */
00686    if (decoded->msg_type == AST_AOC_REQUEST) {
00687       if (decoded->request_flag & AST_AOC_REQUEST_S) {
00688          encoded->flags |= AST_AOC_ENCODED_REQUEST_S;
00689       }
00690       if (decoded->request_flag & AST_AOC_REQUEST_D) {
00691          encoded->flags |= AST_AOC_ENCODED_REQUEST_D;
00692       }
00693       if (decoded->request_flag & AST_AOC_REQUEST_E) {
00694          encoded->flags |= AST_AOC_ENCODED_REQUEST_E;
00695       }
00696    } else if ((decoded->msg_type == AST_AOC_D) || (decoded->msg_type == AST_AOC_E)) {
00697       switch (decoded->charge_type) {
00698       case AST_AOC_CHARGE_UNIT:
00699          encoded->flags |= AST_AOC_ENCODED_CHARGE_UNIT;
00700          break;
00701       case AST_AOC_CHARGE_CURRENCY:
00702          encoded->flags |= AST_AOC_ENCODED_CHARGE_CURRENCY;
00703          break;
00704       case AST_AOC_CHARGE_FREE:
00705          encoded->flags |= AST_AOC_ENCODED_CHARGE_FREE;
00706       case AST_AOC_CHARGE_NA:
00707       default:
00708          encoded->flags |= AST_AOC_ENCODED_CHARGE_NA;
00709          break;
00710       }
00711 
00712       if (decoded->total_type == AST_AOC_SUBTOTAL) {
00713          encoded->flags |= AST_AOC_ENCODED_CHARGE_SUBTOTAL;
00714       }
00715    }
00716 
00717    /* --- Set Version Number --- */
00718    encoded->version = AST_AOC_ENCODE_VERSION;
00719 
00720    /* set the output size  */
00721    *out_size = size;
00722 
00723    if (aoc_debug_enabled) {
00724       aoc_display_decoded_debug(decoded, 0, chan);
00725    }
00726 
00727    return encoded;
00728 }
00729 
00730 static int aoc_s_add_entry(struct ast_aoc_decoded *decoded, struct ast_aoc_s_entry *entry)
00731 {
00732    if (decoded->aoc_s_count >= ARRAY_LEN(decoded->aoc_s_entries)) {
00733       return -1;
00734    }
00735 
00736    decoded->aoc_s_entries[decoded->aoc_s_count] = *entry;
00737    decoded->aoc_s_count++;
00738 
00739    return 0;
00740 }
00741 
00742 
00743 unsigned int ast_aoc_s_get_count(struct ast_aoc_decoded *decoded)
00744 {
00745    return decoded->aoc_s_count;
00746 }
00747 
00748 const struct ast_aoc_s_entry *ast_aoc_s_get_rate_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
00749 {
00750    if (entry_number >= decoded->aoc_s_count) {
00751       return NULL;
00752    }
00753 
00754    return (const struct ast_aoc_s_entry *) &decoded->aoc_s_entries[entry_number];
00755 }
00756 
00757 int ast_aoc_s_add_rate_duration(struct ast_aoc_decoded *decoded,
00758    enum ast_aoc_s_charged_item charged_item,
00759    unsigned int amount,
00760    enum ast_aoc_currency_multiplier multiplier,
00761    const char *currency_name,
00762    unsigned long time,
00763    enum ast_aoc_time_scale time_scale,
00764    unsigned long granularity_time,
00765    enum ast_aoc_time_scale granularity_time_scale,
00766    int step_function)
00767 {
00768 
00769    struct ast_aoc_s_entry entry = { 0, };
00770 
00771    entry.charged_item = charged_item;
00772    entry.rate_type = AST_AOC_RATE_TYPE_DURATION;
00773    entry.rate.duration.amount = amount;
00774    entry.rate.duration.multiplier = multiplier;
00775    entry.rate.duration.time = time;
00776    entry.rate.duration.time_scale = time_scale;
00777    entry.rate.duration.granularity_time = granularity_time;
00778    entry.rate.duration.granularity_time_scale = granularity_time_scale;
00779    entry.rate.duration.charging_type = step_function ? 1 : 0;
00780 
00781    if (!ast_strlen_zero(currency_name)) {
00782       ast_copy_string(entry.rate.duration.currency_name, currency_name, sizeof(entry.rate.duration.currency_name));
00783    }
00784 
00785    return aoc_s_add_entry(decoded, &entry);
00786 }
00787 
00788 int ast_aoc_s_add_rate_flat(struct ast_aoc_decoded *decoded,
00789    enum ast_aoc_s_charged_item charged_item,
00790    unsigned int amount,
00791    enum ast_aoc_currency_multiplier multiplier,
00792    const char *currency_name)
00793 {
00794    struct ast_aoc_s_entry entry = { 0, };
00795 
00796    entry.charged_item = charged_item;
00797    entry.rate_type = AST_AOC_RATE_TYPE_FLAT;
00798    entry.rate.flat.amount = amount;
00799    entry.rate.flat.multiplier = multiplier;
00800 
00801    if (!ast_strlen_zero(currency_name)) {
00802       ast_copy_string(entry.rate.flat.currency_name, currency_name, sizeof(entry.rate.flat.currency_name));
00803    }
00804 
00805    return aoc_s_add_entry(decoded, &entry);
00806 }
00807 
00808 
00809 int ast_aoc_s_add_rate_volume(struct ast_aoc_decoded *decoded,
00810    enum ast_aoc_s_charged_item charged_item,
00811    enum ast_aoc_volume_unit volume_unit,
00812    unsigned int amount,
00813    enum ast_aoc_currency_multiplier multiplier,
00814    const char *currency_name)
00815 {
00816    struct ast_aoc_s_entry entry = { 0, };
00817 
00818    entry.charged_item = charged_item;
00819    entry.rate_type = AST_AOC_RATE_TYPE_VOLUME;
00820    entry.rate.volume.multiplier = multiplier;
00821    entry.rate.volume.amount = amount;
00822    entry.rate.volume.volume_unit = volume_unit;
00823 
00824    if (!ast_strlen_zero(currency_name)) {
00825       ast_copy_string(entry.rate.volume.currency_name, currency_name, sizeof(entry.rate.volume.currency_name));
00826    }
00827 
00828    return aoc_s_add_entry(decoded, &entry);
00829 }
00830 
00831 int ast_aoc_s_add_rate_special_charge_code(struct ast_aoc_decoded *decoded,
00832    enum ast_aoc_s_charged_item charged_item,
00833    unsigned int code)
00834 {
00835    struct ast_aoc_s_entry entry = { 0, };
00836 
00837    entry.charged_item = charged_item;
00838    entry.rate_type = AST_AOC_RATE_TYPE_SPECIAL_CODE;
00839    entry.rate.special_code = code;
00840 
00841    return aoc_s_add_entry(decoded, &entry);
00842 }
00843 
00844 int ast_aoc_s_add_rate_free(struct ast_aoc_decoded *decoded,
00845    enum ast_aoc_s_charged_item charged_item,
00846    int from_beginning)
00847 {
00848    struct ast_aoc_s_entry entry = { 0, };
00849 
00850    entry.charged_item = charged_item;
00851    entry.rate_type = from_beginning ? AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING : AST_AOC_RATE_TYPE_FREE;
00852 
00853    return aoc_s_add_entry(decoded, &entry);
00854 }
00855 
00856 int ast_aoc_s_add_rate_na(struct ast_aoc_decoded *decoded,
00857    enum ast_aoc_s_charged_item charged_item)
00858 {
00859    struct ast_aoc_s_entry entry = { 0, };
00860 
00861    entry.charged_item = charged_item;
00862    entry.rate_type = AST_AOC_RATE_TYPE_NA;
00863 
00864    return aoc_s_add_entry(decoded, &entry);
00865 }
00866 
00867 int ast_aoc_s_add_special_arrangement(struct ast_aoc_decoded *decoded,
00868    unsigned int code)
00869 {
00870    struct ast_aoc_s_entry entry = { 0, };
00871 
00872    entry.charged_item = AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
00873    entry.rate_type = AST_AOC_RATE_TYPE_SPECIAL_CODE;
00874    entry.rate.special_code = code;
00875 
00876    return aoc_s_add_entry(decoded, &entry);
00877 }
00878 
00879 enum ast_aoc_type ast_aoc_get_msg_type(struct ast_aoc_decoded *decoded)
00880 {
00881    return decoded->msg_type;
00882 }
00883 
00884 enum ast_aoc_charge_type ast_aoc_get_charge_type(struct ast_aoc_decoded *decoded)
00885 {
00886    return decoded->charge_type;
00887 }
00888 
00889 enum ast_aoc_request ast_aoc_get_request(struct ast_aoc_decoded *decoded)
00890 {
00891    return decoded->request_flag;
00892 }
00893 
00894 int ast_aoc_set_total_type(struct ast_aoc_decoded *decoded,
00895    const enum ast_aoc_total_type type)
00896 {
00897    decoded->total_type = type;
00898    return 0;
00899 }
00900 
00901 enum ast_aoc_total_type ast_aoc_get_total_type(struct ast_aoc_decoded *decoded)
00902 {
00903    return decoded->total_type;
00904 }
00905 
00906 int ast_aoc_set_currency_info(struct ast_aoc_decoded *decoded,
00907       const unsigned int amount,
00908       const enum ast_aoc_currency_multiplier multiplier,
00909       const char *name)
00910 {
00911 
00912    if (!ast_strlen_zero(name)) {
00913       ast_copy_string(decoded->currency_name, name, sizeof(decoded->currency_name));
00914    }
00915 
00916    decoded->currency_amount = amount;
00917 
00918    if (multiplier && (multiplier < AST_AOC_MULT_NUM_ENTRIES)) {
00919       decoded->multiplier = multiplier;
00920    } else {
00921       decoded->multiplier = AST_AOC_MULT_ONE;
00922    }
00923 
00924    return 0;
00925 }
00926 
00927 unsigned int ast_aoc_get_currency_amount(struct ast_aoc_decoded *decoded)
00928 {
00929    return decoded->currency_amount;
00930 }
00931 
00932 enum ast_aoc_currency_multiplier ast_aoc_get_currency_multiplier(struct ast_aoc_decoded *decoded)
00933 {
00934    return decoded->multiplier;
00935 }
00936 
00937 const char *ast_aoc_get_currency_multiplier_decimal(struct ast_aoc_decoded *decoded)
00938 {
00939    switch (decoded->multiplier) {
00940    case AST_AOC_MULT_ONETHOUSANDTH:
00941       return "0.001";
00942    case AST_AOC_MULT_ONEHUNDREDTH:
00943       return "0.01";
00944    case AST_AOC_MULT_ONETENTH:
00945       return "0.1";
00946    case AST_AOC_MULT_ONE:
00947       return "1.0";
00948    case AST_AOC_MULT_TEN:
00949       return "10.0";
00950    case AST_AOC_MULT_HUNDRED:
00951       return "100.0";
00952    case AST_AOC_MULT_THOUSAND:
00953       return "1000.0";
00954    default:
00955       return "1.0";
00956    }
00957 }
00958 
00959 const char *ast_aoc_get_currency_name(struct ast_aoc_decoded *decoded)
00960 {
00961    return decoded->currency_name;
00962 }
00963 
00964 int ast_aoc_add_unit_entry(struct ast_aoc_decoded *decoded,
00965       const unsigned int amount_is_present,
00966       const unsigned int amount,
00967       const unsigned int type_is_present,
00968       const unsigned int type)
00969 {
00970    if ((decoded->msg_type == AST_AOC_REQUEST) ||
00971       (decoded->unit_count >= ARRAY_LEN(decoded->unit_list))) {
00972       return -1;
00973    }
00974 
00975    if (!amount_is_present && !type_is_present) {
00976       return -1;
00977    }
00978 
00979    decoded->unit_list[decoded->unit_count].valid_amount = amount_is_present;
00980    if (amount_is_present) {
00981       decoded->unit_list[decoded->unit_count].amount = amount;
00982    } else {
00983       decoded->unit_list[decoded->unit_count].amount = 0;
00984    }
00985 
00986    decoded->unit_list[decoded->unit_count].valid_type = type_is_present;
00987    if (type_is_present) {
00988       decoded->unit_list[decoded->unit_count].type = type;
00989    } else {
00990       decoded->unit_list[decoded->unit_count].type = 0;
00991    }
00992    decoded->unit_count++;
00993 
00994    return 0;
00995 }
00996 
00997 const struct ast_aoc_unit_entry *ast_aoc_get_unit_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
00998 {
00999    if (entry_number >= decoded->unit_count) {
01000       return NULL;
01001    }
01002 
01003    return (const struct ast_aoc_unit_entry *) &decoded->unit_list[entry_number];
01004 }
01005 
01006 unsigned int ast_aoc_get_unit_count(struct ast_aoc_decoded *decoded)
01007 {
01008    return decoded->unit_count;
01009 }
01010 
01011 int ast_aoc_set_billing_id(struct ast_aoc_decoded *decoded, const enum ast_aoc_billing_id id)
01012 {
01013    if ((id >= AST_AOC_BILLING_NUM_ENTRIES) || (id < AST_AOC_BILLING_NA)) {
01014       return -1;
01015    }
01016 
01017    decoded->billing_id = id;
01018 
01019    return 0;
01020 }
01021 
01022 enum ast_aoc_billing_id ast_aoc_get_billing_id(struct ast_aoc_decoded *decoded)
01023 {
01024    return decoded->billing_id;
01025 }
01026 
01027 int ast_aoc_set_association_id(struct ast_aoc_decoded *decoded, const int id)
01028 {
01029    if (decoded->msg_type != AST_AOC_E) {
01030       return -1;
01031    }
01032    memset(&decoded->charging_association, 0, sizeof(decoded->charging_association));
01033    decoded->charging_association.charging_type = AST_AOC_CHARGING_ASSOCIATION_ID;
01034    decoded->charging_association.charge.id = id;
01035    return 0;
01036 }
01037 
01038 const struct ast_aoc_charging_association *ast_aoc_get_association_info(struct ast_aoc_decoded *decoded)
01039 {
01040    return &decoded->charging_association;
01041 }
01042 
01043 int ast_aoc_set_association_number(struct ast_aoc_decoded *decoded, const char *num, uint8_t plan)
01044 {
01045    if ((decoded->msg_type != AST_AOC_E) || ast_strlen_zero(num)) {
01046       return -1;
01047    }
01048    memset(&decoded->charging_association, 0, sizeof(decoded->charging_association));
01049    decoded->charging_association.charging_type = AST_AOC_CHARGING_ASSOCIATION_NUMBER;
01050    decoded->charging_association.charge.number.plan = plan;
01051    ast_copy_string(decoded->charging_association.charge.number.number, num, sizeof(decoded->charging_association.charge.number.number));
01052 
01053    return 0;
01054 }
01055 
01056 int ast_aoc_set_termination_request(struct ast_aoc_decoded *decoded)
01057 {
01058    if (decoded->msg_type != AST_AOC_REQUEST) {
01059       return -1;
01060    }
01061    decoded->termination_request = 1;
01062 
01063    return 0;
01064 }
01065 
01066 int ast_aoc_get_termination_request(struct ast_aoc_decoded *decoded)
01067 {
01068    return decoded->termination_request;
01069 }
01070 
01071 /*!
01072  * \internal
01073  * \brief Convert AST_AOC_VOLUME_UNIT to string.
01074  * \since 1.8
01075  *
01076  * \param value Value to convert to string.
01077  *
01078  * \return String equivalent.
01079  */
01080 static const char *aoc_volume_unit_str(enum ast_aoc_volume_unit value)
01081 {
01082    const char *str;
01083 
01084    switch (value) {
01085    default:
01086    case AST_AOC_VOLUME_UNIT_OCTET:
01087       str = "Octet";
01088       break;
01089    case AST_AOC_VOLUME_UNIT_SEGMENT:
01090       str = "Segment";
01091       break;
01092    case AST_AOC_VOLUME_UNIT_MESSAGE:
01093       str = "Message";
01094       break;
01095    }
01096    return str;
01097 }
01098 
01099 /*!
01100  * \internal
01101  * \brief Convert ast_aoc_charged_item to string.
01102  * \since 1.8
01103  *
01104  * \param value Value to convert to string.
01105  *
01106  * \return String equivalent.
01107  */
01108 static const char *aoc_charged_item_str(enum ast_aoc_s_charged_item value)
01109 {
01110    const char *str;
01111 
01112    switch (value) {
01113    default:
01114    case AST_AOC_CHARGED_ITEM_NA:
01115       str = "NotAvailable";
01116       break;
01117    case AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT:
01118       str = "SpecialArrangement";
01119       break;
01120    case AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION:
01121       str = "BasicCommunication";
01122       break;
01123    case AST_AOC_CHARGED_ITEM_CALL_ATTEMPT:
01124       str = "CallAttempt";
01125       break;
01126    case AST_AOC_CHARGED_ITEM_CALL_SETUP:
01127       str = "CallSetup";
01128       break;
01129    case AST_AOC_CHARGED_ITEM_USER_USER_INFO:
01130       str = "UserUserInfo";
01131       break;
01132    case AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE:
01133       str = "SupplementaryService";
01134       break;
01135    }
01136    return str;
01137 }
01138 
01139 /*!
01140  * \internal
01141  * \brief Convert ast_aoc_total_type to string.
01142  * \since 1.8
01143  *
01144  * \param value Value to convert to string.
01145  *
01146  * \return String equivalent.
01147  */
01148 static const char *aoc_type_of_totaling_str(enum ast_aoc_total_type value)
01149 {
01150    const char *str;
01151 
01152    switch (value) {
01153    default:
01154    case AST_AOC_SUBTOTAL:
01155       str = "SubTotal";
01156       break;
01157    case AST_AOC_TOTAL:
01158       str = "Total";
01159       break;
01160    }
01161    return str;
01162 }
01163 
01164 /*!
01165  * \internal
01166  * \brief Convert ast_aoc_rate_type to string.
01167  * \since 1.8
01168  *
01169  * \param value Value to convert to string.
01170  *
01171  * \return String equivalent.
01172  */
01173 static const char *aoc_rate_type_str(enum ast_aoc_s_rate_type value)
01174 {
01175    const char *str;
01176 
01177    switch (value) {
01178    default:
01179    case AST_AOC_RATE_TYPE_NA:
01180       str = "NotAvailable";
01181       break;
01182    case AST_AOC_RATE_TYPE_FREE:
01183       str = "Free";
01184       break;
01185    case AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING:
01186       str = "FreeFromBeginning";
01187       break;
01188    case AST_AOC_RATE_TYPE_DURATION:
01189       str = "Duration";
01190       break;
01191    case AST_AOC_RATE_TYPE_FLAT:
01192       str = "Flat";
01193       break;
01194    case AST_AOC_RATE_TYPE_VOLUME:
01195       str = "Volume";
01196       break;
01197    case AST_AOC_RATE_TYPE_SPECIAL_CODE:
01198       str = "SpecialCode";
01199       break;
01200    }
01201    return str;
01202 }
01203 
01204 /*!
01205  * \internal
01206  * \brief Convert AST_AOC_TIME_SCALE to string.
01207  * \since 1.8
01208  *
01209  * \param value Value to convert to string.
01210  *
01211  * \return String equivalent.
01212  */
01213 static const char *aoc_scale_str(enum ast_aoc_time_scale value)
01214 {
01215    const char *str;
01216 
01217    switch (value) {
01218    default:
01219    case AST_AOC_TIME_SCALE_HUNDREDTH_SECOND:
01220       str = "OneHundredthSecond";
01221       break;
01222    case AST_AOC_TIME_SCALE_TENTH_SECOND:
01223       str = "OneTenthSecond";
01224       break;
01225    case AST_AOC_TIME_SCALE_SECOND:
01226       str = "Second";
01227       break;
01228    case AST_AOC_TIME_SCALE_TEN_SECOND:
01229       str = "TenSeconds";
01230       break;
01231    case AST_AOC_TIME_SCALE_MINUTE:
01232       str = "Minute";
01233       break;
01234    case AST_AOC_TIME_SCALE_HOUR:
01235       str = "Hour";
01236       break;
01237    case AST_AOC_TIME_SCALE_DAY:
01238       str = "Day";
01239       break;
01240    }
01241    return str;
01242 }
01243 
01244 static const char *aoc_charge_type_str(enum ast_aoc_charge_type value)
01245 {
01246    const char *str;
01247 
01248    switch (value) {
01249    default:
01250    case AST_AOC_CHARGE_NA:
01251       str = "NotAvailable";
01252       break;
01253    case AST_AOC_CHARGE_FREE:
01254       str = "Free";
01255       break;
01256    case AST_AOC_CHARGE_CURRENCY:
01257       str = "Currency";
01258       break;
01259    case AST_AOC_CHARGE_UNIT:
01260       str = "Units";
01261       break;
01262    }
01263 
01264    return str;
01265 }
01266 
01267 static const char *aoc_multiplier_str(enum ast_aoc_currency_multiplier mult)
01268 {
01269    switch (mult) {
01270    case AST_AOC_MULT_ONETHOUSANDTH:
01271       return "1/1000";
01272    case AST_AOC_MULT_ONEHUNDREDTH:
01273       return "1/100";
01274    case AST_AOC_MULT_ONETENTH:
01275       return "1/10";
01276    case AST_AOC_MULT_ONE:
01277       return "1";
01278    case AST_AOC_MULT_TEN:
01279       return "10";
01280    case AST_AOC_MULT_HUNDRED:
01281       return "100";
01282    case AST_AOC_MULT_THOUSAND:
01283       return "1000";
01284    case AST_AOC_MULT_NUM_ENTRIES:
01285       break;
01286    }
01287    return "1";
01288 }
01289 
01290 static const char *aoc_billingid_str(enum ast_aoc_billing_id billing_id)
01291 {
01292    switch (billing_id) {
01293    case AST_AOC_BILLING_NORMAL:
01294       return "Normal";
01295    case AST_AOC_BILLING_REVERSE_CHARGE:
01296       return "Reverse";
01297    case AST_AOC_BILLING_CREDIT_CARD:
01298       return "CreditCard";
01299    case AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL:
01300       return "CallForwardingUnconditional";
01301    case AST_AOC_BILLING_CALL_FWD_BUSY:
01302       return "CallForwardingBusy";
01303    case AST_AOC_BILLING_CALL_FWD_NO_REPLY:
01304       return "CallForwardingNoReply";
01305    case AST_AOC_BILLING_CALL_DEFLECTION:
01306       return "CallDeflection";
01307    case AST_AOC_BILLING_CALL_TRANSFER:
01308       return "CallTransfer";
01309    case AST_AOC_BILLING_NA:
01310       return "NotAvailable";
01311    case AST_AOC_BILLING_NUM_ENTRIES:
01312       break;
01313    }
01314    return "NotAvailable";
01315 }
01316 
01317 int ast_aoc_test_encode_decode_match(struct ast_aoc_decoded *decoded)
01318 {
01319    struct ast_aoc_decoded *new_decoded = NULL;
01320    struct ast_aoc_encoded *encoded = NULL;
01321    size_t size;
01322    int res = 0;
01323 
01324    if (!(encoded = ast_aoc_encode(decoded, &size, NULL))) {
01325       return -1;
01326    }
01327 
01328    if (!(new_decoded = ast_aoc_decode(encoded, size, NULL))) {
01329       ast_free(encoded);
01330       return -1;
01331    }
01332 
01333    if (memcmp(new_decoded, decoded, sizeof(struct ast_aoc_decoded))) {
01334       res = -1;
01335    }
01336 
01337    ast_aoc_destroy_decoded(new_decoded);
01338    ast_aoc_destroy_encoded(encoded);
01339    return res;
01340 }
01341 
01342 static char *aoc_cli_debug_enable(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01343 {
01344    switch (cmd) {
01345    case CLI_INIT:
01346       e->command = "aoc set debug";
01347       e->usage =
01348          "Usage: 'aoc set debug on' to enable aoc debug, 'aoc set debug off' to disable debug.\n";
01349       return NULL;
01350    case CLI_GENERATE:
01351       return NULL;
01352    case CLI_HANDLER:
01353       if (a->argc != 4) {
01354          return CLI_SHOWUSAGE;
01355       } else if(ast_true(a->argv[3])) {
01356          ast_cli(a->fd, "aoc debug enabled\n");
01357          aoc_debug_enabled = 1;
01358       } else if (ast_false(a->argv[3])) {
01359          ast_cli(a->fd, "aoc debug disabled\n");
01360          aoc_debug_enabled = 0;
01361       } else {
01362          return CLI_SHOWUSAGE;
01363       }
01364    }
01365 
01366    return CLI_SUCCESS;
01367 }
01368 
01369 /*!
01370  * \internal
01371  * \brief Append the time structure to the event message string.
01372  * \since 1.8
01373  *
01374  * \param msg Event message string being built.
01375  * \param prefix Prefix to add to the amount lines.
01376  * \param name Name of the time structure to convert.
01377  * \param time Data to convert.
01378  * \param scale Data to convert.
01379  *
01380  * \return Nothing
01381  */
01382 static void aoc_time_str(struct ast_str **msg, const char *prefix, const char *name, unsigned long time, enum ast_aoc_time_scale scale)
01383 {
01384    ast_str_append(msg, 0, "%s/%s/Length: %lu\r\n", prefix, name, time);
01385    ast_str_append(msg, 0, "%s/%s/Scale: %s\r\n", prefix, name,
01386       aoc_scale_str(scale));
01387 }
01388 
01389 /*!
01390  * \internal
01391  * \brief Append the amount structure to the event message string.
01392  * \since 1.8
01393  *
01394  * \param msg Event message string being built.
01395  * \param prefix Prefix to add to the amount lines.
01396  * \param amount Data to convert.
01397  * \param multipler to convert
01398  *
01399  * \return Nothing
01400  */
01401 static void aoc_amount_str(struct ast_str **msg, const char *prefix, unsigned int amount, enum ast_aoc_currency_multiplier mult)
01402 {
01403    static const char name[] = "Amount";
01404 
01405    ast_str_append(msg, 0, "%s/%s/Cost: %u\r\n", prefix, name, amount);
01406    ast_str_append(msg, 0, "%s/%s/Multiplier: %s\r\n", prefix, name,
01407       aoc_multiplier_str(mult));
01408 }
01409 
01410 static void aoc_request_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
01411 {
01412    if (decoded->request_flag) {
01413       ast_str_append(msg, 0, "AOCRequest:");
01414       if (decoded->request_flag & AST_AOC_REQUEST_S) {
01415          ast_str_append(msg, 0, "S");
01416       }
01417       if (decoded->request_flag & AST_AOC_REQUEST_D) {
01418          ast_str_append(msg, 0, "D");
01419       }
01420       if (decoded->request_flag & AST_AOC_REQUEST_E) {
01421          ast_str_append(msg, 0, "E");
01422       }
01423       ast_str_append(msg, 0, "\r\n");
01424 
01425    } else {
01426       ast_str_append(msg, 0, "AOCRequest: NONE\r\n");
01427    }
01428 }
01429 
01430 static void aoc_s_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
01431 {
01432    const char *rate_str;
01433    char prefix[32];
01434    int idx;
01435 
01436    ast_str_append(msg, 0, "NumberRates: %d\r\n", decoded->aoc_s_count);
01437    for (idx = 0; idx < decoded->aoc_s_count; ++idx) {
01438       snprintf(prefix, sizeof(prefix), "Rate(%d)", idx);
01439 
01440       ast_str_append(msg, 0, "%s/Chargeable: %s\r\n", prefix,
01441          aoc_charged_item_str(decoded->aoc_s_entries[idx].charged_item));
01442       if (decoded->aoc_s_entries[idx].charged_item == AST_AOC_CHARGED_ITEM_NA) {
01443          continue;
01444       }
01445       rate_str = aoc_rate_type_str(decoded->aoc_s_entries[idx].rate_type);
01446       ast_str_append(msg, 0, "%s/Type: %s\r\n", prefix, rate_str);
01447       switch (decoded->aoc_s_entries[idx].rate_type) {
01448       case AST_AOC_RATE_TYPE_DURATION:
01449          strcat(prefix, "/");
01450          strcat(prefix, rate_str);
01451          ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
01452             decoded->aoc_s_entries[idx].rate.duration.currency_name);
01453          aoc_amount_str(msg, prefix,
01454             decoded->aoc_s_entries[idx].rate.duration.amount,
01455             decoded->aoc_s_entries[idx].rate.duration.multiplier);
01456          ast_str_append(msg, 0, "%s/ChargingType: %s\r\n", prefix,
01457             decoded->aoc_s_entries[idx].rate.duration.charging_type ?
01458             "StepFunction" : "ContinuousCharging");
01459          aoc_time_str(msg, prefix, "Time",
01460             decoded->aoc_s_entries[idx].rate.duration.time,
01461             decoded->aoc_s_entries[idx].rate.duration.time_scale);
01462          if (decoded->aoc_s_entries[idx].rate.duration.granularity_time) {
01463             aoc_time_str(msg, prefix, "Granularity",
01464                decoded->aoc_s_entries[idx].rate.duration.granularity_time,
01465                decoded->aoc_s_entries[idx].rate.duration.granularity_time_scale);
01466          }
01467          break;
01468       case AST_AOC_RATE_TYPE_FLAT:
01469          strcat(prefix, "/");
01470          strcat(prefix, rate_str);
01471          ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
01472             decoded->aoc_s_entries[idx].rate.flat.currency_name);
01473          aoc_amount_str(msg, prefix,
01474             decoded->aoc_s_entries[idx].rate.flat.amount,
01475             decoded->aoc_s_entries[idx].rate.flat.multiplier);
01476          break;
01477       case AST_AOC_RATE_TYPE_VOLUME:
01478          strcat(prefix, "/");
01479          strcat(prefix, rate_str);
01480          ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
01481             decoded->aoc_s_entries[idx].rate.volume.currency_name);
01482          aoc_amount_str(msg, prefix,
01483             decoded->aoc_s_entries[idx].rate.volume.amount,
01484             decoded->aoc_s_entries[idx].rate.volume.multiplier);
01485          ast_str_append(msg, 0, "%s/Unit: %s\r\n", prefix,
01486             aoc_volume_unit_str(decoded->aoc_s_entries[idx].rate.volume.volume_unit));
01487          break;
01488       case AST_AOC_RATE_TYPE_SPECIAL_CODE:
01489          ast_str_append(msg, 0, "%s/%s: %d\r\n", prefix, rate_str,
01490             decoded->aoc_s_entries[idx].rate.special_code);
01491          break;
01492       default:
01493          break;
01494       }
01495    }
01496 }
01497 
01498 static void aoc_d_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
01499 {
01500    const char *charge_str;
01501    int idx;
01502    char prefix[32];
01503 
01504    charge_str = aoc_charge_type_str(decoded->charge_type);
01505    ast_str_append(msg, 0, "Type: %s\r\n", charge_str);
01506 
01507    switch (decoded->charge_type) {
01508    case AST_AOC_CHARGE_CURRENCY:
01509    case AST_AOC_CHARGE_UNIT:
01510       ast_str_append(msg, 0, "BillingID: %s\r\n",
01511          aoc_billingid_str(decoded->billing_id));
01512       ast_str_append(msg, 0, "TypeOfCharging: %s\r\n",
01513          aoc_type_of_totaling_str(decoded->total_type));
01514       break;
01515    default:
01516       break;
01517    }
01518 
01519    switch (decoded->charge_type) {
01520    case AST_AOC_CHARGE_CURRENCY:
01521       ast_str_append(msg, 0, "%s: %s\r\n", charge_str,
01522          decoded->currency_name);
01523       aoc_amount_str(msg, charge_str,
01524          decoded->currency_amount,
01525          decoded->multiplier);
01526       break;
01527    case AST_AOC_CHARGE_UNIT:
01528       ast_str_append(msg, 0, "%s/NumberItems: %d\r\n", charge_str,
01529          decoded->unit_count);
01530       for (idx = 0; idx < decoded->unit_count; ++idx) {
01531          snprintf(prefix, sizeof(prefix), "%s/Item(%d)", charge_str, idx);
01532          if (decoded->unit_list[idx].valid_amount) {
01533             ast_str_append(msg, 0, "%s/NumberOf: %u\r\n", prefix,
01534                decoded->unit_list[idx].amount);
01535          }
01536          if (decoded->unit_list[idx].valid_type) {
01537             ast_str_append(msg, 0, "%s/TypeOf: %u\r\n", prefix,
01538                decoded->unit_list[idx].type);
01539          }
01540       }
01541       break;
01542    default:
01543       break;
01544    }
01545 }
01546 
01547 static void aoc_e_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
01548 {
01549    const char *charge_str;
01550    int idx;
01551    char prefix[32];
01552 
01553    charge_str = "ChargingAssociation";
01554 
01555    switch (decoded->charging_association.charging_type) {
01556    case AST_AOC_CHARGING_ASSOCIATION_NUMBER:
01557       snprintf(prefix, sizeof(prefix), "%s/Number", charge_str);
01558       ast_str_append(msg, 0, "%s: %s\r\n", prefix,
01559          decoded->charging_association.charge.number.number);
01560       ast_str_append(msg, 0, "%s/Plan: %d\r\n", prefix,
01561          decoded->charging_association.charge.number.plan);
01562       break;
01563    case AST_AOC_CHARGING_ASSOCIATION_ID:
01564       ast_str_append(msg, 0, "%s/ID: %d\r\n", charge_str, decoded->charging_association.charge.id);
01565       break;
01566    case AST_AOC_CHARGING_ASSOCIATION_NA:
01567    default:
01568       break;
01569    }
01570 
01571    charge_str = aoc_charge_type_str(decoded->charge_type);
01572    ast_str_append(msg, 0, "Type: %s\r\n", charge_str);
01573    switch (decoded->charge_type) {
01574    case AST_AOC_CHARGE_CURRENCY:
01575    case AST_AOC_CHARGE_UNIT:
01576       ast_str_append(msg, 0, "BillingID: %s\r\n",
01577          aoc_billingid_str(decoded->billing_id));
01578       break;
01579    default:
01580       break;
01581    }
01582    switch (decoded->charge_type) {
01583    case AST_AOC_CHARGE_CURRENCY:
01584       ast_str_append(msg, 0, "%s: %s\r\n", charge_str,
01585          decoded->currency_name);
01586       aoc_amount_str(msg, charge_str,
01587          decoded->currency_amount,
01588          decoded->multiplier);
01589       break;
01590    case AST_AOC_CHARGE_UNIT:
01591       ast_str_append(msg, 0, "%s/NumberItems: %d\r\n", charge_str,
01592          decoded->unit_count);
01593       for (idx = 0; idx < decoded->unit_count; ++idx) {
01594          snprintf(prefix, sizeof(prefix), "%s/Item(%d)", charge_str, idx);
01595          if (decoded->unit_list[idx].valid_amount) {
01596             ast_str_append(msg, 0, "%s/NumberOf: %u\r\n", prefix,
01597                decoded->unit_list[idx].amount);
01598          }
01599          if (decoded->unit_list[idx].valid_type) {
01600             ast_str_append(msg, 0, "%s/TypeOf: %u\r\n", prefix,
01601                decoded->unit_list[idx].type);
01602          }
01603       }
01604       break;
01605    default:
01606       break;
01607    }
01608 }
01609 
01610 static struct ast_json *units_to_json(const struct ast_aoc_decoded *decoded)
01611 {
01612    int i;
01613    struct ast_json *units = ast_json_array_create();
01614 
01615    if (!units) {
01616       return ast_json_null();
01617    }
01618 
01619    for (i = 0; i < decoded->unit_count; ++i) {
01620       struct ast_json *unit = ast_json_object_create();
01621 
01622       if (decoded->unit_list[i].valid_amount) {
01623          ast_json_object_set(
01624             unit, "NumberOf", ast_json_stringf(
01625                "%u", decoded->unit_list[i].amount));
01626          }
01627 
01628       if (decoded->unit_list[i].valid_type) {
01629          ast_json_object_set(
01630             unit, "TypeOf", ast_json_stringf(
01631                "%u", decoded->unit_list[i].type));
01632       }
01633 
01634       if (ast_json_array_append(units, unit)) {
01635          break;
01636       }
01637    }
01638 
01639    return units;
01640 }
01641 
01642 static struct ast_json *currency_to_json(const char *name, int cost,
01643                 enum ast_aoc_currency_multiplier mult)
01644 {
01645    return ast_json_pack("{s:s, s:i, s:s}",   "Name", name,
01646               "Cost", cost, "Multiplier", aoc_multiplier_str(mult));
01647 }
01648 
01649 static struct ast_json *charge_to_json(const struct ast_aoc_decoded *decoded)
01650 {
01651    RAII_VAR(struct ast_json *, obj, NULL, ast_json_unref);
01652    const char *obj_type;
01653 
01654    if (decoded->charge_type != AST_AOC_CHARGE_CURRENCY &&
01655        decoded->charge_type != AST_AOC_CHARGE_UNIT) {
01656       return ast_json_pack("{s:s}", "Type",
01657                  aoc_charge_type_str(decoded->charge_type));
01658    }
01659 
01660    if (decoded->charge_type == AST_AOC_CHARGE_CURRENCY) {
01661       obj_type = "Currency";
01662       obj = currency_to_json(decoded->currency_name, decoded->currency_amount,
01663                    decoded->multiplier);
01664    } else { /* decoded->charge_type == AST_AOC_CHARGE_UNIT */
01665       obj_type = "Units";
01666       obj = units_to_json(decoded);
01667    }
01668 
01669    return ast_json_pack(
01670       "{s:s, s:s, s:s, s:O}",
01671       "Type", aoc_charge_type_str(decoded->charge_type),
01672       "BillingID", aoc_billingid_str(decoded->billing_id),
01673       "TotalType", aoc_type_of_totaling_str(decoded->total_type),
01674       obj_type, obj);
01675 }
01676 
01677 static struct ast_json *association_to_json(const struct ast_aoc_decoded *decoded)
01678 {
01679    switch (decoded->charging_association.charging_type) {
01680    case AST_AOC_CHARGING_ASSOCIATION_NUMBER:
01681       return ast_json_pack(
01682          "{s:s, s:i}",
01683          "Number", decoded->charging_association.charge.number.number,
01684          "Plan", decoded->charging_association.charge.number.plan);
01685    case AST_AOC_CHARGING_ASSOCIATION_ID:
01686       return ast_json_pack(
01687          "{s:i}", "ID", decoded->charging_association.charge.id);
01688    case AST_AOC_CHARGING_ASSOCIATION_NA:
01689    default:
01690       return ast_json_null();
01691    }
01692 }
01693 
01694 static struct ast_json *s_to_json(const struct ast_aoc_decoded *decoded)
01695 {
01696    int i;
01697    struct ast_json *rates = ast_json_array_create();
01698 
01699    if (!rates) {
01700       return ast_json_null();
01701    }
01702 
01703    for (i = 0; i < decoded->aoc_s_count; ++i) {
01704       struct ast_json *rate = ast_json_object_create();
01705       RAII_VAR(struct ast_json *, type, NULL, ast_json_unref);
01706       RAII_VAR(struct ast_json *, currency, NULL, ast_json_unref);
01707       const char *charge_item = aoc_charged_item_str(
01708          decoded->aoc_s_entries[i].charged_item);
01709 
01710       if (decoded->aoc_s_entries[i].charged_item == AST_AOC_CHARGED_ITEM_NA) {
01711          rate = ast_json_pack("{s:s}", "Chargeable", charge_item);
01712          if (ast_json_array_append(rates, rate)) {
01713             break;
01714          }
01715          continue;
01716       }
01717 
01718       switch (decoded->aoc_s_entries[i].rate_type) {
01719       case AST_AOC_RATE_TYPE_DURATION:
01720       {
01721          RAII_VAR(struct ast_json *, time, NULL, ast_json_unref);
01722          RAII_VAR(struct ast_json *, granularity, NULL, ast_json_unref);
01723 
01724          currency = currency_to_json(
01725             decoded->aoc_s_entries[i].rate.duration.currency_name,
01726             decoded->aoc_s_entries[i].rate.duration.amount,
01727             decoded->aoc_s_entries[i].rate.duration.multiplier);
01728 
01729          time = ast_json_pack(
01730             "{s:i, s:s}",
01731             "Length", decoded->aoc_s_entries[i].rate.duration.time,
01732             "Scale", decoded->aoc_s_entries[i].rate.duration.time_scale);
01733 
01734          if (decoded->aoc_s_entries[i].rate.duration.granularity_time) {
01735             granularity = ast_json_pack(
01736                "{s:i, s:s}",
01737                "Length", decoded->aoc_s_entries[i].rate.duration.granularity_time,
01738                "Scale", decoded->aoc_s_entries[i].rate.duration.granularity_time_scale);
01739          }
01740 
01741          type = ast_json_pack("{s:O, s:s, s:O, s:O}", "Currency", currency, "ChargingType",
01742                     decoded->aoc_s_entries[i].rate.duration.charging_type ?
01743                     "StepFunction" : "ContinuousCharging", "Time", time,
01744                     "Granularity", granularity ? granularity : ast_json_null());
01745 
01746          break;
01747       }
01748       case AST_AOC_RATE_TYPE_FLAT:
01749          currency = currency_to_json(
01750             decoded->aoc_s_entries[i].rate.flat.currency_name,
01751             decoded->aoc_s_entries[i].rate.flat.amount,
01752             decoded->aoc_s_entries[i].rate.flat.multiplier);
01753 
01754          type = ast_json_pack("{s:O}", "Currency", currency);
01755          break;
01756       case AST_AOC_RATE_TYPE_VOLUME:
01757          currency = currency_to_json(
01758             decoded->aoc_s_entries[i].rate.volume.currency_name,
01759             decoded->aoc_s_entries[i].rate.volume.amount,
01760             decoded->aoc_s_entries[i].rate.volume.multiplier);
01761 
01762          type = ast_json_pack(
01763             "{s:s, s:O}", "Unit", aoc_volume_unit_str(
01764                decoded->aoc_s_entries[i].rate.volume.volume_unit),
01765             "Currency", currency);
01766          break;
01767       case AST_AOC_RATE_TYPE_SPECIAL_CODE:
01768          type = ast_json_pack("{s:i}", "SpecialCode",
01769                    decoded->aoc_s_entries[i].rate.special_code);
01770          break;
01771       default:
01772          break;
01773       }
01774 
01775       rate = ast_json_pack("{s:s, s:O}", "Chargeable", charge_item,
01776                  aoc_rate_type_str(decoded->aoc_s_entries[i].rate_type), type);
01777       if (ast_json_array_append(rates, rate)) {
01778          break;
01779       }
01780    }
01781    return rates;
01782 }
01783 
01784 static struct ast_json *d_to_json(const struct ast_aoc_decoded *decoded)
01785 {
01786    return ast_json_pack("{s:o}", "Charge", charge_to_json(decoded));
01787 }
01788 
01789 static struct ast_json *e_to_json(const struct ast_aoc_decoded *decoded)
01790 {
01791    return ast_json_pack("{s:o, s:o}",
01792               "ChargingAssociation", association_to_json(decoded),
01793               "Charge", charge_to_json(decoded));
01794 }
01795 
01796 struct aoc_event_blob {
01797    /*! Channel AOC event is associated with (NULL for unassociated) */
01798    struct ast_channel_snapshot *snapshot;
01799    /*! AOC JSON blob of data */
01800    struct ast_json *blob;
01801 };
01802 
01803 static void aoc_event_blob_dtor(void *obj)
01804 {
01805    struct aoc_event_blob *aoc_event = obj;
01806 
01807    ao2_cleanup(aoc_event->snapshot);
01808    ast_json_unref(aoc_event->blob);
01809 }
01810 
01811 /*!
01812  * \internal
01813  * \brief Publish an AOC event.
01814  * \since 13.3.0
01815  *
01816  * \param chan Channel associated with the AOC event. (May be NULL if no channel)
01817  * \param msg_type What kind of AOC event.
01818  * \param blob AOC data blob to publish.
01819  *
01820  * \return Nothing
01821  */
01822 static void aoc_publish_blob(struct ast_channel *chan, struct stasis_message_type *msg_type, struct ast_json *blob)
01823 {
01824    struct stasis_message *msg;
01825    struct aoc_event_blob *aoc_event;
01826 
01827    if (!blob || ast_json_is_null(blob)) {
01828       /* No AOC blob information?  Nothing to send an event about. */
01829       return;
01830    }
01831 
01832    aoc_event = ao2_alloc_options(sizeof(*aoc_event), aoc_event_blob_dtor,
01833       AO2_ALLOC_OPT_LOCK_NOLOCK);
01834    if (!aoc_event) {
01835       return;
01836    }
01837 
01838    if (chan) {
01839       aoc_event->snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
01840       if (!aoc_event->snapshot) {
01841          ao2_ref(aoc_event, -1);
01842          return;
01843       }
01844    }
01845    aoc_event->blob = ast_json_ref(blob);
01846 
01847    msg = stasis_message_create(msg_type, aoc_event);
01848    ao2_ref(aoc_event, -1);
01849 
01850    stasis_publish(ast_manager_get_topic(), msg);
01851 }
01852 
01853 static struct ast_manager_event_blob *aoc_to_ami(struct stasis_message *message,
01854                    const char *event_name)
01855 {
01856    struct aoc_event_blob *aoc_event = stasis_message_data(message);
01857    struct ast_str *channel = NULL;
01858    struct ast_str *aoc;
01859    struct ast_manager_event_blob *ev = NULL;
01860 
01861    if (aoc_event->snapshot) {
01862       channel = ast_manager_build_channel_state_string(aoc_event->snapshot);
01863       if (!channel) {
01864          return NULL;
01865       }
01866    }
01867 
01868    aoc = ast_manager_str_from_json_object(aoc_event->blob, NULL);
01869    if (aoc && !ast_strlen_zero(ast_str_buffer(aoc))) {
01870       ev = ast_manager_event_blob_create(EVENT_FLAG_AOC, event_name, "%s%s",
01871          AS_OR(channel, ""), ast_str_buffer(aoc));
01872    }
01873 
01874    ast_free(aoc);
01875    ast_free(channel);
01876    return ev;
01877 }
01878 
01879 static struct ast_manager_event_blob *aoc_s_to_ami(struct stasis_message *message)
01880 {
01881    return aoc_to_ami(message, "AOC-S");
01882 }
01883 
01884 static struct ast_manager_event_blob *aoc_d_to_ami(struct stasis_message *message)
01885 {
01886    return aoc_to_ami(message, "AOC-D");
01887 }
01888 
01889 static struct ast_manager_event_blob *aoc_e_to_ami(struct stasis_message *message)
01890 {
01891    return aoc_to_ami(message, "AOC-E");
01892 }
01893 
01894 struct stasis_message_type *aoc_s_type(void);
01895 struct stasis_message_type *aoc_d_type(void);
01896 struct stasis_message_type *aoc_e_type(void);
01897 
01898 STASIS_MESSAGE_TYPE_DEFN(
01899    aoc_s_type,
01900    .to_ami = aoc_s_to_ami);
01901 
01902 STASIS_MESSAGE_TYPE_DEFN(
01903    aoc_d_type,
01904    .to_ami = aoc_d_to_ami);
01905 
01906 STASIS_MESSAGE_TYPE_DEFN(
01907    aoc_e_type,
01908    .to_ami = aoc_e_to_ami);
01909 
01910 int ast_aoc_manager_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan)
01911 {
01912    struct ast_json *blob;
01913    struct stasis_message_type *msg_type;
01914 
01915    if (!decoded) {
01916       return -1;
01917    }
01918 
01919    switch (decoded->msg_type) {
01920    case AST_AOC_S:
01921       blob = s_to_json(decoded);
01922       msg_type = aoc_s_type();
01923       break;
01924    case AST_AOC_D:
01925       blob = d_to_json(decoded);
01926       msg_type = aoc_d_type();
01927       break;
01928    case AST_AOC_E:
01929       blob = e_to_json(decoded);
01930       msg_type = aoc_e_type();
01931       break;
01932    default:
01933       /* events for AST_AOC_REQUEST are not generated here */
01934       return 0;
01935    }
01936 
01937    aoc_publish_blob(chan, msg_type, blob);
01938    ast_json_unref(blob);
01939    return 0;
01940 }
01941 
01942 int ast_aoc_decoded2str(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
01943 {
01944    if (!decoded || !msg) {
01945       return -1;
01946    }
01947 
01948    switch (decoded->msg_type) {
01949    case AST_AOC_S:
01950       ast_str_append(msg, 0, "AOC-S\r\n");
01951       aoc_s_event(decoded, msg);
01952       break;
01953    case AST_AOC_D:
01954       ast_str_append(msg, 0, "AOC-D\r\n");
01955       aoc_d_event(decoded, msg);
01956       break;
01957    case AST_AOC_E:
01958       ast_str_append(msg, 0, "AOC-E\r\n");
01959       aoc_e_event(decoded, msg);
01960       break;
01961    case AST_AOC_REQUEST:
01962       ast_str_append(msg, 0, "AOC-Request\r\n");
01963       aoc_request_event(decoded, msg);
01964       break;
01965    }
01966 
01967    return 0;
01968 }
01969 
01970 static void aoc_display_decoded_debug(const struct ast_aoc_decoded *decoded, int decoding, struct ast_channel *chan)
01971 {
01972    struct ast_str *msg;
01973 
01974    if (!decoded || !(msg = ast_str_create(1024))) {
01975       return;
01976    }
01977 
01978    if (decoding) {
01979       ast_str_append(&msg, 0, "---- DECODED AOC MSG ----\r\n");
01980    } else {
01981       ast_str_append(&msg, 0, "---- ENCODED AOC MSG ----\r\n");
01982    }
01983    if (chan) {
01984       ast_str_append(&msg, 0, "CHANNEL: %s\r\n", ast_channel_name(chan));
01985    }
01986 
01987    if (ast_aoc_decoded2str(decoded, &msg)) {
01988       ast_free(msg);
01989       return;
01990    }
01991 
01992    ast_verb(1, "%s\r\n", ast_str_buffer(msg));
01993    ast_free(msg);
01994 }
01995 
01996 static struct ast_cli_entry aoc_cli[] = {
01997    AST_CLI_DEFINE(aoc_cli_debug_enable, "enable cli debugging of AOC messages"),
01998 };
01999 
02000 static void aoc_shutdown(void)
02001 {
02002    STASIS_MESSAGE_TYPE_CLEANUP(aoc_s_type);
02003    STASIS_MESSAGE_TYPE_CLEANUP(aoc_d_type);
02004    STASIS_MESSAGE_TYPE_CLEANUP(aoc_e_type);
02005 
02006    ast_cli_unregister_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
02007 }
02008 int ast_aoc_cli_init(void)
02009 {
02010    STASIS_MESSAGE_TYPE_INIT(aoc_s_type);
02011    STASIS_MESSAGE_TYPE_INIT(aoc_d_type);
02012    STASIS_MESSAGE_TYPE_INIT(aoc_e_type);
02013 
02014    ast_register_cleanup(aoc_shutdown);
02015    return ast_cli_register_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
02016 }

Generated on Thu Apr 16 06:27:06 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6