From: Richard Mudgett Date: Wed, 2 Jun 2010 17:13:53 +0000 (+0000) Subject: Add ETSI Advice Of Charge (AOC) event reporting. X-Git-Tag: 11.0.0-beta1~2937 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=28264c52b96f9c3b5b911be430b43cf679d426b5;p=thirdparty%2Fasterisk.git Add ETSI Advice Of Charge (AOC) event reporting. This feature generates AMI events in the new aoc event class from the events passed up by libpri. Review: https://reviewboard.asterisk.org/r/537/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@267008 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/CHANGES b/CHANGES index 5b9e3cd347..86057b5568 100644 --- a/CHANGES +++ b/CHANGES @@ -364,6 +364,8 @@ Asterisk Manager Interface in a MixMonitor recording. * The 'iax2 show peers' output is now similar to the expected output of 'sip show peers'. + * Added Advice-Of-Charge events (AOC-S, AOC-D, and AOC-E) in the new + aoc event class. Channel Event Logging --------------------- diff --git a/channels/sig_pri.c b/channels/sig_pri.c index 846f8b0551..44f5d2384a 100644 --- a/channels/sig_pri.c +++ b/channels/sig_pri.c @@ -2054,6 +2054,651 @@ static void sig_pri_cc_link_canceled(struct sig_pri_pri *pri, long cc_id, int is } #endif /* defined(HAVE_PRI_CCSS) */ +#if defined(HAVE_PRI_AOC_EVENTS) +/*! + * \internal + * \brief Convert PRI_AOC_CHARGED_ITEM to string. + * \since 1.8 + * + * \param value Value to convert to string. + * + * \return String equivalent. + */ +static const char *sig_pri_aoc_charged_item_str(enum PRI_AOC_CHARGED_ITEM value) +{ + const char *str; + + switch (value) { + default: + case PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE: + str = "NotAvailable"; + break; + case PRI_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT: + str = "SpecialArrangement"; + break; + case PRI_AOC_CHARGED_ITEM_BASIC_COMMUNICATION: + str = "BasicCommunication"; + break; + case PRI_AOC_CHARGED_ITEM_CALL_ATTEMPT: + str = "CallAttempt"; + break; + case PRI_AOC_CHARGED_ITEM_CALL_SETUP: + str = "CallSetup"; + break; + case PRI_AOC_CHARGED_ITEM_USER_USER_INFO: + str = "UserUserInfo"; + break; + case PRI_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE: + str = "SupplementaryService"; + break; + } + return str; +} +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ + +#if defined(HAVE_PRI_AOC_EVENTS) +/*! + * \internal + * \brief Convert PRI_AOC_RATE_TYPE to string. + * \since 1.8 + * + * \param value Value to convert to string. + * + * \return String equivalent. + */ +static const char *sig_pri_aoc_rate_type_str(enum PRI_AOC_RATE_TYPE value) +{ + const char *str; + + switch (value) { + default: + case PRI_AOC_RATE_TYPE_NOT_AVAILABLE: + str = "NotAvailable"; + break; + case PRI_AOC_RATE_TYPE_FREE: + str = "Free"; + break; + case PRI_AOC_RATE_TYPE_FREE_FROM_BEGINNING: + str = "FreeFromBeginning"; + break; + case PRI_AOC_RATE_TYPE_DURATION: + str = "Duration"; + break; + case PRI_AOC_RATE_TYPE_FLAT: + str = "Flat"; + break; + case PRI_AOC_RATE_TYPE_VOLUME: + str = "Volume"; + break; + case PRI_AOC_RATE_TYPE_SPECIAL_CODE: + str = "SpecialCode"; + break; + } + return str; +} +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ + +#if defined(HAVE_PRI_AOC_EVENTS) +/*! + * \internal + * \brief Convert PRI_AOC_VOLUME_UNIT to string. + * \since 1.8 + * + * \param value Value to convert to string. + * + * \return String equivalent. + */ +static const char *sig_pri_aoc_volume_unit_str(enum PRI_AOC_VOLUME_UNIT value) +{ + const char *str; + + switch (value) { + default: + case PRI_AOC_VOLUME_UNIT_OCTET: + str = "Octet"; + break; + case PRI_AOC_VOLUME_UNIT_SEGMENT: + str = "Segment"; + break; + case PRI_AOC_VOLUME_UNIT_MESSAGE: + str = "Message"; + break; + } + return str; +} +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ + +#if defined(HAVE_PRI_AOC_EVENTS) +/*! + * \internal + * \brief Convert PRI_AOC_MULTIPLIER to string. + * \since 1.8 + * + * \param value Value to convert to string. + * + * \return String equivalent. + */ +static const char *sig_pri_aoc_multiplier_str(enum PRI_AOC_MULTIPLIER value) +{ + const char *str; + + switch (value) { + default: + case PRI_AOC_MULTIPLIER_THOUSANDTH: + str = "1/1000"; + break; + case PRI_AOC_MULTIPLIER_HUNDREDTH: + str = "1/100"; + break; + case PRI_AOC_MULTIPLIER_TENTH: + str = "1/10"; + break; + case PRI_AOC_MULTIPLIER_ONE: + str = "1"; + break; + case PRI_AOC_MULTIPLIER_TEN: + str = "10"; + break; + case PRI_AOC_MULTIPLIER_HUNDRED: + str = "100"; + break; + case PRI_AOC_MULTIPLIER_THOUSAND: + str = "1000"; + break; + } + return str; +} +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ + +#if defined(HAVE_PRI_AOC_EVENTS) +/*! + * \internal + * \brief Convert PRI_AOC_TIME_SCALE to string. + * \since 1.8 + * + * \param value Value to convert to string. + * + * \return String equivalent. + */ +static const char *sig_pri_aoc_scale_str(enum PRI_AOC_TIME_SCALE value) +{ + const char *str; + + switch (value) { + default: + case PRI_AOC_TIME_SCALE_HUNDREDTH_SECOND: + str = "OneHundredthSecond"; + break; + case PRI_AOC_TIME_SCALE_TENTH_SECOND: + str = "OneTenthSecond"; + break; + case PRI_AOC_TIME_SCALE_SECOND: + str = "Second"; + break; + case PRI_AOC_TIME_SCALE_TEN_SECOND: + str = "TenSeconds"; + break; + case PRI_AOC_TIME_SCALE_MINUTE: + str = "Minute"; + break; + case PRI_AOC_TIME_SCALE_HOUR: + str = "Hour"; + break; + case PRI_AOC_TIME_SCALE_DAY: + str = "Day"; + break; + } + return str; +} +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ + +#if defined(HAVE_PRI_AOC_EVENTS) +/*! + * \internal + * \brief Convert PRI_AOC_DE_CHARGE to string. + * \since 1.8 + * + * \param value Value to convert to string. + * + * \return String equivalent. + */ +static const char *sig_pri_aoc_de_charge_str(enum PRI_AOC_DE_CHARGE value) +{ + const char *str; + + switch (value) { + default: + case PRI_AOC_DE_CHARGE_NOT_AVAILABLE: + str = "NotAvailable"; + break; + case PRI_AOC_DE_CHARGE_FREE: + str = "Free"; + break; + case PRI_AOC_DE_CHARGE_CURRENCY: + str = "Currency"; + break; + case PRI_AOC_DE_CHARGE_UNITS: + str = "Units"; + break; + } + return str; +} +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ + +#if defined(HAVE_PRI_AOC_EVENTS) +/*! + * \internal + * \brief Convert PRI_AOC_D_BILLING_ID to string. + * \since 1.8 + * + * \param value Value to convert to string. + * + * \return String equivalent. + */ +static const char *sig_pri_aoc_d_billing_id_str(enum PRI_AOC_D_BILLING_ID value) +{ + const char *str; + + switch (value) { + default: + case PRI_AOC_D_BILLING_ID_NOT_AVAILABLE: + str = "NotAvailable"; + break; + case PRI_AOC_D_BILLING_ID_NORMAL: + str = "Normal"; + break; + case PRI_AOC_D_BILLING_ID_REVERSE: + str = "Reverse"; + break; + case PRI_AOC_D_BILLING_ID_CREDIT_CARD: + str = "CreditCard"; + break; + } + return str; +} +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ + +#if defined(HAVE_PRI_AOC_EVENTS) +/*! + * \internal + * \brief Convert PRI_AOC_E_BILLING_ID to string. + * \since 1.8 + * + * \param value Value to convert to string. + * + * \return String equivalent. + */ +static const char *sig_pri_aoc_e_billing_id_str(enum PRI_AOC_E_BILLING_ID value) +{ + const char *str; + + switch (value) { + default: + case PRI_AOC_E_BILLING_ID_NOT_AVAILABLE: + str = "NotAvailable"; + break; + case PRI_AOC_E_BILLING_ID_NORMAL: + str = "Normal"; + break; + case PRI_AOC_E_BILLING_ID_REVERSE: + str = "Reverse"; + break; + case PRI_AOC_E_BILLING_ID_CREDIT_CARD: + str = "CreditCard"; + break; + case PRI_AOC_E_BILLING_ID_CALL_FORWARDING_UNCONDITIONAL: + str = "CallForwardingUnconditional"; + break; + case PRI_AOC_E_BILLING_ID_CALL_FORWARDING_BUSY: + str = "CallForwardingBusy"; + break; + case PRI_AOC_E_BILLING_ID_CALL_FORWARDING_NO_REPLY: + str = "CallForwardingNoReply"; + break; + case PRI_AOC_E_BILLING_ID_CALL_DEFLECTION: + str = "CallDeflection"; + break; + case PRI_AOC_E_BILLING_ID_CALL_TRANSFER: + str = "CallTransfer"; + break; + } + return str; +} +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ + +#if defined(HAVE_PRI_AOC_EVENTS) +/*! + * \internal + * \brief Append the amount structure to the event message string. + * \since 1.8 + * + * \param msg Event message string being built. + * \param prefix Prefix to add to the amount lines. + * \param amount Data to convert. + * + * \return Nothing + */ +static void sig_pri_aoc_amount(struct ast_str **msg, const char *prefix, const struct pri_aoc_amount *amount) +{ + static const char name[] = "Amount"; + + ast_str_append(msg, 0, "%s/%s/Cost: %ld\r\n", prefix, name, amount->cost); + ast_str_append(msg, 0, "%s/%s/Multiplier: %s\r\n", prefix, name, + sig_pri_aoc_multiplier_str(amount->multiplier)); +} +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ + +#if defined(HAVE_PRI_AOC_EVENTS) +/*! + * \internal + * \brief Append the time structure to the event message string. + * \since 1.8 + * + * \param msg Event message string being built. + * \param prefix Prefix to add to the amount lines. + * \param name Name of the time structure to convert. + * \param time Data to convert. + * + * \return Nothing + */ +static void sig_pri_aoc_time(struct ast_str **msg, const char *prefix, const char *name, const struct pri_aoc_time *time) +{ + ast_str_append(msg, 0, "%s/%s/Length: %ld\r\n", prefix, name, time->length); + ast_str_append(msg, 0, "%s/%s/Scale: %s\r\n", prefix, name, + sig_pri_aoc_scale_str(time->scale)); +} +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ + +#if defined(HAVE_PRI_AOC_EVENTS) +/*! + * \internal + * \brief Handle the AOC-S event. + * \since 1.8 + * + * \param aoc_s AOC-S event parameters. + * \param owner Asterisk channel associated with the call. + * + * \note Assumes the pri->lock is already obtained. + * \note Assumes the owner channel lock is already obtained. + * + * \return Nothing + */ +static void sig_pri_aoc_s_event(const struct pri_subcmd_aoc_s *aoc_s, struct ast_channel *owner) +{ + struct ast_str *msg; + const char *rate_str; + char prefix[32]; + int idx; + + msg = ast_str_create(4096); + if (!msg) { + return; + } + + ast_str_append(&msg, 0, "Channel: %s\r\n", owner->name); + ast_str_append(&msg, 0, "UniqueID: %s\r\n", owner->uniqueid); + + ast_str_append(&msg, 0, "NumberRates: %d\r\n", aoc_s->num_items); + for (idx = 0; idx < aoc_s->num_items; ++idx) { + snprintf(prefix, sizeof(prefix), "Rate(%d)", idx); + + ast_str_append(&msg, 0, "%s/Chargeable: %s\r\n", prefix, + sig_pri_aoc_charged_item_str(aoc_s->item[idx].chargeable)); + if (aoc_s->item[idx].chargeable == PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE) { + continue; + } + rate_str = sig_pri_aoc_rate_type_str(aoc_s->item[idx].rate_type); + ast_str_append(&msg, 0, "%s/Type: %s\r\n", prefix, rate_str); + switch (aoc_s->item[idx].rate_type) { + case PRI_AOC_RATE_TYPE_DURATION: + strcat(prefix, "/"); + strcat(prefix, rate_str); + ast_str_append(&msg, 0, "%s/Currency: %s\r\n", prefix, + aoc_s->item[idx].rate.duration.currency); + sig_pri_aoc_amount(&msg, prefix, &aoc_s->item[idx].rate.duration.amount); + ast_str_append(&msg, 0, "%s/ChargingType: %s\r\n", prefix, + aoc_s->item[idx].rate.duration.charging_type + ? "StepFunction" : "ContinuousCharging"); + sig_pri_aoc_time(&msg, prefix, "Time", &aoc_s->item[idx].rate.duration.time); + if (aoc_s->item[idx].rate.duration.granularity.length) { + sig_pri_aoc_time(&msg, prefix, "Granularity", + &aoc_s->item[idx].rate.duration.granularity); + } + break; + case PRI_AOC_RATE_TYPE_FLAT: + strcat(prefix, "/"); + strcat(prefix, rate_str); + ast_str_append(&msg, 0, "%s/Currency: %s\r\n", prefix, + aoc_s->item[idx].rate.flat.currency); + sig_pri_aoc_amount(&msg, prefix, &aoc_s->item[idx].rate.flat.amount); + break; + case PRI_AOC_RATE_TYPE_VOLUME: + strcat(prefix, "/"); + strcat(prefix, rate_str); + ast_str_append(&msg, 0, "%s/Currency: %s\r\n", prefix, + aoc_s->item[idx].rate.volume.currency); + sig_pri_aoc_amount(&msg, prefix, &aoc_s->item[idx].rate.volume.amount); + ast_str_append(&msg, 0, "%s/Unit: %s\r\n", prefix, + sig_pri_aoc_volume_unit_str(aoc_s->item[idx].rate.volume.unit)); + break; + case PRI_AOC_RATE_TYPE_SPECIAL_CODE: + ast_str_append(&msg, 0, "%s/%s: %d\r\n", prefix, rate_str, + aoc_s->item[idx].rate.special); + break; + default: + break; + } + } + + ast_manager_event(owner, EVENT_FLAG_AOC, "AOC-S", "%s", ast_str_buffer(msg)); + ast_free(msg); +} +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ + +#if defined(HAVE_PRI_AOC_EVENTS) +/*! + * \internal + * \brief Handle the AOC-D event. + * \since 1.8 + * + * \param aoc_d AOC-D event parameters. + * \param owner Asterisk channel associated with the call. + * + * \note Assumes the pri->lock is already obtained. + * \note Assumes the owner channel lock is already obtained. + * + * \return Nothing + */ +static void sig_pri_aoc_d_event(const struct pri_subcmd_aoc_d *aoc_d, struct ast_channel *owner) +{ + struct ast_str *msg; + const char *charge_str; + int idx; + int num_items; + char prefix[32]; + + msg = ast_str_create(4096); + if (!msg) { + return; + } + + ast_str_append(&msg, 0, "Channel: %s\r\n", owner->name); + ast_str_append(&msg, 0, "UniqueID: %s\r\n", owner->uniqueid); + + charge_str = sig_pri_aoc_de_charge_str(aoc_d->charge); + ast_str_append(&msg, 0, "Type: %s\r\n", charge_str); + switch (aoc_d->charge) { + case PRI_AOC_DE_CHARGE_CURRENCY: + case PRI_AOC_DE_CHARGE_UNITS: + ast_str_append(&msg, 0, "BillingID: %s\r\n", + sig_pri_aoc_d_billing_id_str(aoc_d->billing_id)); + ast_str_append(&msg, 0, "TypeOfCharging: %s\r\n", + aoc_d->billing_accumulation ? "Total" : "SubTotal"); + break; + default: + break; + } + switch (aoc_d->charge) { + case PRI_AOC_DE_CHARGE_CURRENCY: + ast_str_append(&msg, 0, "%s: %s\r\n", charge_str, + aoc_d->recorded.money.currency); + sig_pri_aoc_amount(&msg, charge_str, &aoc_d->recorded.money.amount); + break; + case PRI_AOC_DE_CHARGE_UNITS: + num_items = 0; + for (idx = 0; idx < aoc_d->recorded.unit.num_items; ++idx) { + if (0 <= aoc_d->recorded.unit.item[idx].number + || 0 <= aoc_d->recorded.unit.item[idx].type) { + /* Something is available at this index location so keep it. */ + ++num_items; + } + } + ast_str_append(&msg, 0, "%s/NumberItems: %d\r\n", charge_str, num_items); + num_items = 0; + for (idx = 0; idx < aoc_d->recorded.unit.num_items; ++idx) { + if (aoc_d->recorded.unit.item[idx].number < 0 + && aoc_d->recorded.unit.item[idx].type < 0) { + /* Nothing is available at this index location so skip it. */ + continue; + } + snprintf(prefix, sizeof(prefix), "%s/Item(%d)", charge_str, num_items); + ++num_items; + + if (0 <= aoc_d->recorded.unit.item[idx].number) { + /* Number of units recorded is available */ + ast_str_append(&msg, 0, "%s/NumberOf: %ld\r\n", prefix, + aoc_d->recorded.unit.item[idx].number); + } + if (0 <= aoc_d->recorded.unit.item[idx].type) { + /* Type of units recorded is available */ + ast_str_append(&msg, 0, "%s/TypeOf: %d\r\n", prefix, + aoc_d->recorded.unit.item[idx].type); + } + } + break; + default: + break; + } + + ast_manager_event(owner, EVENT_FLAG_AOC, "AOC-D", "%s", ast_str_buffer(msg)); + ast_free(msg); +} +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ + +#if defined(HAVE_PRI_AOC_EVENTS) +/*! + * \internal + * \brief Handle the AOC-E event. + * \since 1.8 + * + * \param aoc_e AOC-E event parameters. + * \param owner Asterisk channel associated with the call. + * NULL if the event is not associated with an existing call. + * + * \note Assumes the pri->lock is already obtained. + * \note Assumes the owner channel lock is already obtained if associated. + * + * \return Nothing + */ +static void sig_pri_aoc_e_event(const struct pri_subcmd_aoc_e *aoc_e, struct ast_channel *owner) +{ + struct ast_channel *chans[1]; + struct ast_str *msg; + const char *charge_str; + int idx; + int num_items; + char prefix[32]; + + msg = ast_str_create(4096); + if (!msg) { + return; + } + + if (owner) { + ast_str_append(&msg, 0, "Channel: %s\r\n", owner->name); + ast_str_append(&msg, 0, "UniqueID: %s\r\n", owner->uniqueid); + } + + /* If there is no owner then there should be a charging association. */ + charge_str = "ChargingAssociation"; + switch (aoc_e->associated.charging_type) { + case PRI_AOC_E_CHARGING_ASSOCIATION_NUMBER: + if (!aoc_e->associated.charge.number.valid) { + break; + } + snprintf(prefix, sizeof(prefix), "%s/Number", charge_str); + ast_str_append(&msg, 0, "%s: %s\r\n", prefix, + aoc_e->associated.charge.number.str); + ast_str_append(&msg, 0, "%s/Plan: %d\r\n", prefix, + aoc_e->associated.charge.number.plan); + break; + case PRI_AOC_E_CHARGING_ASSOCIATION_ID: + ast_str_append(&msg, 0, "%s/ID: %d\r\n", charge_str, aoc_e->associated.charge.id); + break; + default: + break; + } + + charge_str = sig_pri_aoc_de_charge_str(aoc_e->charge); + ast_str_append(&msg, 0, "Type: %s\r\n", charge_str); + switch (aoc_e->charge) { + case PRI_AOC_DE_CHARGE_CURRENCY: + case PRI_AOC_DE_CHARGE_UNITS: + ast_str_append(&msg, 0, "BillingID: %s\r\n", + sig_pri_aoc_e_billing_id_str(aoc_e->billing_id)); + break; + default: + break; + } + switch (aoc_e->charge) { + case PRI_AOC_DE_CHARGE_CURRENCY: + ast_str_append(&msg, 0, "%s: %s\r\n", charge_str, + aoc_e->recorded.money.currency); + sig_pri_aoc_amount(&msg, charge_str, &aoc_e->recorded.money.amount); + break; + case PRI_AOC_DE_CHARGE_UNITS: + num_items = 0; + for (idx = 0; idx < aoc_e->recorded.unit.num_items; ++idx) { + if (0 <= aoc_e->recorded.unit.item[idx].number + || 0 <= aoc_e->recorded.unit.item[idx].type) { + /* Something is available at this index location so keep it. */ + ++num_items; + } + } + ast_str_append(&msg, 0, "%s/NumberItems: %d\r\n", charge_str, num_items); + num_items = 0; + for (idx = 0; idx < aoc_e->recorded.unit.num_items; ++idx) { + if (aoc_e->recorded.unit.item[idx].number < 0 + && aoc_e->recorded.unit.item[idx].type < 0) { + /* Nothing is available at this index location so skip it. */ + continue; + } + snprintf(prefix, sizeof(prefix), "%s/Item(%d)", charge_str, num_items); + ++num_items; + + if (0 <= aoc_e->recorded.unit.item[idx].number) { + /* Number of units recorded is available */ + ast_str_append(&msg, 0, "%s/NumberOf: %ld\r\n", prefix, + aoc_e->recorded.unit.item[idx].number); + } + if (0 <= aoc_e->recorded.unit.item[idx].type) { + /* Type of units recorded is available */ + ast_str_append(&msg, 0, "%s/TypeOf: %d\r\n", prefix, + aoc_e->recorded.unit.item[idx].type); + } + } + break; + default: + break; + } + + chans[0] = owner; + ast_manager_event_multichan(EVENT_FLAG_AOC, "AOC-E", owner ? 1 : 0, chans, "%s", + ast_str_buffer(msg)); + ast_free(msg); +} +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ + /*! * \internal * \brief TRUE if PRI event came in on a CIS call. @@ -2269,6 +2914,11 @@ static void sig_pri_handle_cis_subcmds(struct sig_pri_pri *pri, int event_id, ao2_ref(monitor, -1); break; #endif /* defined(HAVE_PRI_CCSS) */ +#if defined(HAVE_PRI_AOC_EVENTS) + case PRI_SUBCMD_AOC_E: + sig_pri_aoc_e_event(&subcmd->u.aoc_e, NULL); + break; +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ default: ast_debug(2, "Unknown CIS subcommand(%d) in %s event on span %d.\n", @@ -2524,6 +3174,36 @@ static void sig_pri_handle_subcmds(struct sig_pri_pri *pri, int chanpos, int eve sig_pri_lock_private(pri->pvts[chanpos]); break; #endif /* defined(HAVE_PRI_TRANSFER) */ +#if defined(HAVE_PRI_AOC_EVENTS) + case PRI_SUBCMD_AOC_S: + sig_pri_lock_owner(pri, chanpos); + owner = pri->pvts[chanpos]->owner; + if (owner) { + sig_pri_aoc_s_event(&subcmd->u.aoc_s, owner); + ast_channel_unlock(owner); + } + break; +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ +#if defined(HAVE_PRI_AOC_EVENTS) + case PRI_SUBCMD_AOC_D: + sig_pri_lock_owner(pri, chanpos); + owner = pri->pvts[chanpos]->owner; + if (owner) { + sig_pri_aoc_d_event(&subcmd->u.aoc_d, owner); + ast_channel_unlock(owner); + } + break; +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ +#if defined(HAVE_PRI_AOC_EVENTS) + case PRI_SUBCMD_AOC_E: + sig_pri_lock_owner(pri, chanpos); + owner = pri->pvts[chanpos]->owner; + sig_pri_aoc_e_event(&subcmd->u.aoc_e, owner); + if (owner) { + ast_channel_unlock(owner); + } + break; +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ default: ast_debug(2, "Unknown call subcommand(%d) in %s event on channel %d/%d on span %d.\n", @@ -4933,6 +5613,9 @@ int sig_pri_start_pri(struct sig_pri_pri *pri) #if defined(HAVE_PRI_TRANSFER) pri_transfer_enable(pri->pri, 1); #endif /* defined(HAVE_PRI_TRANSFER) */ +#if defined(HAVE_PRI_AOC_EVENTS) + pri_aoc_events_enable(pri->pri, 1); +#endif /* defined(HAVE_PRI_AOC_EVENTS) */ pri->resetpos = -1; if (ast_pthread_create_background(&pri->master, NULL, pri_dchannel, pri)) { diff --git a/configs/manager.conf.sample b/configs/manager.conf.sample index 7db6751192..3666854997 100644 --- a/configs/manager.conf.sample +++ b/configs/manager.conf.sample @@ -107,6 +107,7 @@ bindaddr = 0.0.0.0 ; originate - Permission to originate new calls. Write-only. ; agi - Output AGI commands executed. Input AGI command to execute. ; cc - Call Completion events. Read-only. +; aoc - Advice Of Charge events. Read-only. ; ;read = system,call,log,verbose,agent,user,config,dtmf,reporting,cdr,dialplan ;write = system,call,agent,user,config,command,reporting,originate diff --git a/configure b/configure index 3fc1983261..02af843ed6 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.ac Revision: 266828 . +# From configure.ac Revision: 266926 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.63 for asterisk 1.6. # @@ -862,6 +862,10 @@ PBX_PRI_TRANSFER PRI_TRANSFER_DIR PRI_TRANSFER_INCLUDE PRI_TRANSFER_LIB +PBX_PRI_AOC_EVENTS +PRI_AOC_EVENTS_DIR +PRI_AOC_EVENTS_INCLUDE +PRI_AOC_EVENTS_LIB PBX_PRI PRI_DIR PRI_INCLUDE @@ -10085,6 +10089,25 @@ fi +PRI_AOC_EVENTS_DESCRIP="ISDN PRI advice of charge supplementary service events" +PRI_AOC_EVENTS_OPTION=pri + +for i in ${ac_mandatory_list}; do + if test "xPRI" = "x$i"; then + ac_mandatory_list="${ac_mandatory_list} PRI_AOC_EVENTS" + break + fi +done + +PBX_PRI_AOC_EVENTS=0 + + + + + + + + PRI_TRANSFER_DESCRIP="ISDN PRI call transfer supplementary service" PRI_TRANSFER_OPTION=pri @@ -35462,6 +35485,273 @@ fi +if test "x${PBX_PRI_AOC_EVENTS}" != "x1" -a "${USE_PRI_AOC_EVENTS}" != "no"; then + pbxlibdir="" + # if --with-PRI_AOC_EVENTS=DIR has been specified, use it. + if test "x${PRI_AOC_EVENTS_DIR}" != "x"; then + if test -d ${PRI_AOC_EVENTS_DIR}/lib; then + pbxlibdir="-L${PRI_AOC_EVENTS_DIR}/lib" + else + pbxlibdir="-L${PRI_AOC_EVENTS_DIR}" + fi + fi + pbxfuncname="pri_aoc_events_enable" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_PRI_AOC_EVENTS_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for ${pbxfuncname} in -lpri" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; } +if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpri ${pbxlibdir} $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + eval "$as_ac_Lib=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Lib=no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +ac_res=`eval 'as_val=${'$as_ac_Lib'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_Lib'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + AST_PRI_AOC_EVENTS_FOUND=yes +else + AST_PRI_AOC_EVENTS_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_PRI_AOC_EVENTS_FOUND}" = "yes"; then + PRI_AOC_EVENTS_LIB="${pbxlibdir} -lpri " + # if --with-PRI_AOC_EVENTS=DIR has been specified, use it. + if test "x${PRI_AOC_EVENTS_DIR}" != "x"; then + PRI_AOC_EVENTS_INCLUDE="-I${PRI_AOC_EVENTS_DIR}/include" + fi + PRI_AOC_EVENTS_INCLUDE="${PRI_AOC_EVENTS_INCLUDE} " + if test "xlibpri.h" = "x" ; then # no header, assume found + PRI_AOC_EVENTS_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${PRI_AOC_EVENTS_INCLUDE}" + if test "${ac_cv_header_libpri_h+set}" = set; then + { $as_echo "$as_me:$LINENO: checking for libpri.h" >&5 +$as_echo_n "checking for libpri.h... " >&6; } +if test "${ac_cv_header_libpri_h+set}" = set; then + $as_echo_n "(cached) " >&6 +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_libpri_h" >&5 +$as_echo "$ac_cv_header_libpri_h" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking libpri.h usability" >&5 +$as_echo_n "checking libpri.h usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking libpri.h presence" >&5 +$as_echo_n "checking libpri.h presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: libpri.h: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: libpri.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: libpri.h: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: libpri.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: libpri.h: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: libpri.h: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: libpri.h: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: libpri.h: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: libpri.h: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: libpri.h: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: libpri.h: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: libpri.h: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: libpri.h: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: libpri.h: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: libpri.h: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: libpri.h: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ------------------------------- ## +## Report this to www.asterisk.org ## +## ------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for libpri.h" >&5 +$as_echo_n "checking for libpri.h... " >&6; } +if test "${ac_cv_header_libpri_h+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_cv_header_libpri_h=$ac_header_preproc +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_libpri_h" >&5 +$as_echo "$ac_cv_header_libpri_h" >&6; } + +fi +if test "x$ac_cv_header_libpri_h" = x""yes; then + PRI_AOC_EVENTS_HEADER_FOUND=1 +else + PRI_AOC_EVENTS_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${PRI_AOC_EVENTS_HEADER_FOUND}" = "x0" ; then + PRI_AOC_EVENTS_LIB="" + PRI_AOC_EVENTS_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + PRI_AOC_EVENTS_LIB="" + fi + PBX_PRI_AOC_EVENTS=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_PRI_AOC_EVENTS 1 +_ACEOF + + fi + fi +fi + + + if test "x${PBX_PRI_TRANSFER}" != "x1" -a "${USE_PRI_TRANSFER}" != "no"; then pbxlibdir="" # if --with-PRI_TRANSFER=DIR has been specified, use it. diff --git a/configure.ac b/configure.ac index d4de3c0d5c..27dc580a72 100644 --- a/configure.ac +++ b/configure.ac @@ -341,6 +341,7 @@ AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres]) AST_EXT_LIB_SETUP([POPT], [popt], [popt]) AST_EXT_LIB_SETUP([PORTAUDIO], [PortAudio], [portaudio]) AST_EXT_LIB_SETUP([PRI], [ISDN PRI], [pri]) +AST_EXT_LIB_SETUP_DEPENDENT([PRI_AOC_EVENTS], [ISDN PRI advice of charge supplementary service events], [PRI], [pri]) AST_EXT_LIB_SETUP_DEPENDENT([PRI_TRANSFER], [ISDN PRI call transfer supplementary service], [PRI], [pri]) AST_EXT_LIB_SETUP_DEPENDENT([PRI_CCSS], [ISDN PRI call completion supplementary service], [PRI], [pri]) AST_EXT_LIB_SETUP_DEPENDENT([PRI_HANGUP_FIX], [ISDN PRI hangup fix], [PRI], [pri]) @@ -1591,6 +1592,7 @@ AST_EXT_LIB_CHECK([POPT], [popt], [poptStrerror], [popt.h]) AST_EXT_LIB_CHECK([PORTAUDIO], [portaudio], [Pa_GetDeviceCount], [portaudio.h]) AST_EXT_LIB_CHECK([PRI], [pri], [pri_connected_line_update], [libpri.h]) +AST_EXT_LIB_CHECK([PRI_AOC_EVENTS], [pri], [pri_aoc_events_enable], [libpri.h]) AST_EXT_LIB_CHECK([PRI_TRANSFER], [pri], [pri_transfer_enable], [libpri.h]) AST_EXT_LIB_CHECK([PRI_CCSS], [pri], [pri_cc_enable], [libpri.h]) AST_EXT_LIB_CHECK([PRI_HANGUP_FIX], [pri], [pri_hangup_fix_enable], [libpri.h]) diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index dc4c74c9ab..fb519741e6 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -532,6 +532,10 @@ /* Define to 1 if you have the ISDN PRI library. */ #undef HAVE_PRI +/* Define to 1 if you have the ISDN PRI advice of charge supplementary service + events library. */ +#undef HAVE_PRI_AOC_EVENTS + /* Define to 1 if you have the ISDN PRI call hold library. */ #undef HAVE_PRI_CALL_HOLD diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h index 34595dee26..4fbb1d2021 100644 --- a/include/asterisk/manager.h +++ b/include/asterisk/manager.h @@ -83,6 +83,7 @@ #define EVENT_FLAG_AGI (1 << 13) /* AGI events */ #define EVENT_FLAG_HOOKRESPONSE (1 << 14) /* Hook Response */ #define EVENT_FLAG_CC (1 << 15) /* Call Completion events */ +#define EVENT_FLAG_AOC (1 << 16) /* Advice Of Charge events */ /*@} */ /*! \brief Export manager structures */ diff --git a/main/manager.c b/main/manager.c index 5baa53bcc9..43be08e60a 100644 --- a/main/manager.c +++ b/main/manager.c @@ -990,6 +990,7 @@ static const struct permalias { { EVENT_FLAG_ORIGINATE, "originate" }, { EVENT_FLAG_AGI, "agi" }, { EVENT_FLAG_CC, "cc" }, + { EVENT_FLAG_AOC, "aoc" }, { INT_MAX, "all" }, { 0, "none" }, };