[svn-commits] dvossel: branch dvossel/generic_aoc r252648 - in /team/dvossel/generic_aoc: c...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Mar 15 17:21:46 CDT 2010


Author: dvossel
Date: Mon Mar 15 17:21:42 2010
New Revision: 252648

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=252648
Log:
addition of generic aoc changes

Modified:
    team/dvossel/generic_aoc/channels/chan_sip.c
    team/dvossel/generic_aoc/channels/sip/include/sip.h
    team/dvossel/generic_aoc/configs/sip.conf.sample
    team/dvossel/generic_aoc/include/asterisk/frame.h
    team/dvossel/generic_aoc/main/channel.c
    team/dvossel/generic_aoc/main/manager.c

Modified: team/dvossel/generic_aoc/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/generic_aoc/channels/chan_sip.c?view=diff&rev=252648&r1=252647&r2=252648
==============================================================================
--- team/dvossel/generic_aoc/channels/chan_sip.c (original)
+++ team/dvossel/generic_aoc/channels/chan_sip.c Mon Mar 15 17:21:42 2010
@@ -261,6 +261,7 @@
 #include "asterisk/event.h"
 #include "asterisk/stun.h"
 #include "asterisk/cel.h"
+#include "asterisk/aoc.h"
 #include "sip/include/sip.h"
 #include "sip/include/globals.h"
 #include "sip/include/config_parser.h"
@@ -803,7 +804,7 @@
 static int regobjs = 0;       /*!< Registry objects */
 /* }@ */
 
-static struct ast_flags global_flags[2] = {{0}};  /*!< global SIP_ flags */
+static struct ast_flags global_flags[3] = {{0}};  /*!< global SIP_ flags */
 static int global_t38_maxdatagram;                /*!< global T.38 FaxMaxDatagram override */
 
 static char used_context[AST_MAX_CONTEXT];        /*!< name of automatically created context for unloading */
@@ -1274,6 +1275,7 @@
 static int transmit_publish(struct sip_epa_entry *epa_entry, enum sip_publish_type publish_type, const char * const explicit_uri);
 static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init, const char * const explicit_uri);
 static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version, int oldsdp);
+static int transmit_info_with_aoc(struct sip_pvt *p, struct ast_aoc_decoded *decoded);
 static int transmit_info_with_digit(struct sip_pvt *p, const char digit, unsigned int duration);
 static int transmit_info_with_vidupdate(struct sip_pvt *p);
 static int transmit_message_with_text(struct sip_pvt *p, const char *text);
@@ -4699,6 +4701,7 @@
 
 	ast_copy_flags(&dialog->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&dialog->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+	ast_copy_flags(&dialog->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY);
 	dialog->capability = peer->capability;
 	dialog->prefs = peer->prefs;
 	if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_T38SUPPORT)) {
@@ -6206,6 +6209,18 @@
 	case AST_CONTROL_REDIRECTING:
 		update_redirecting(p, data, datalen);
 		break;
+	case AST_CONTROL_AOC:
+		if (ast_test_flag(&p->flags[2], SIP_PAGE3_SNOM_AOC)) {
+			struct ast_aoc_decoded *decoded = ast_aoc_decode((struct ast_aoc_encoded *) data, datalen);
+			if (decoded) {
+				transmit_info_with_aoc(p, decoded);
+				ast_aoc_destroy_decoded(decoded);
+			} else {
+				ast_log(LOG_ERROR, "Error decoding indicated AOC data\n");
+				res = -1;
+			}
+		}
+		break;
 	case -1:
 		res = -1;
 		break;
@@ -6843,6 +6858,7 @@
 	/* Copy global flags to this PVT at setup. */
 	ast_copy_flags(&p->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&p->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+	ast_copy_flags(&p->flags[2], &global_flags[2], SIP_PAGE3_FLAGS_TO_COPY);
 
 	p->do_history = recordhistory;
 
@@ -11822,6 +11838,53 @@
 	*/
 }
 
+/*! \brief Send SIP INFO advice of charge message */
+static int transmit_info_with_aoc(struct sip_pvt *p, struct ast_aoc_decoded *decoded)
+{
+	struct sip_request req;
+	struct ast_str *str = ast_str_alloca(512);
+	const struct ast_aoc_unit_entry *unit_entry = ast_aoc_get_unit_info(decoded, 0);
+	enum ast_aoc_charge_type charging = ast_aoc_get_charge_type(decoded);
+
+	reqprep(&req, p, SIP_INFO, 0, 1);
+
+	if (ast_aoc_get_msg_type(decoded) == AOC_D) {
+		ast_str_append(&str, 0, "type=active;");
+	} else if (ast_aoc_get_msg_type(decoded) == AOC_E) {
+		ast_str_append(&str, 0, "type=terminated;");
+	} else {
+		/* unsupported message type */
+		return -1;
+	}
+
+	switch (charging) {
+	case AOC_CHARGE_FREE:
+		ast_str_append(&str, 0, "free-of-charge;");
+		break;
+	case AOC_CHARGE_CURRENCY:
+		ast_str_append(&str, 0, "charging;");
+		ast_str_append(&str, 0, "charging-info=currency;");
+		ast_str_append(&str, 0, "amount=%u;", ast_aoc_get_currency_amount(decoded));
+		ast_str_append(&str, 0, "multiplier=%s;", ast_aoc_get_currency_multiplier_decimal(decoded));
+		if (!ast_strlen_zero(ast_aoc_get_currency_name(decoded))) {
+			ast_str_append(&str, 0, "currency=%s;", ast_aoc_get_currency_name(decoded));
+		}
+		break;
+	case AOC_CHARGE_UNIT:
+		ast_str_append(&str, 0, "charging;");
+		ast_str_append(&str, 0, "charging-info=pulse;");
+		if (unit_entry) {
+			ast_str_append(&str, 0, "recorded-units=%u;", unit_entry->amount);
+		}
+		break;
+	default:
+		ast_str_append(&str, 0, "not-available;");
+	};
+
+	add_header(&req, "AOC", ast_str_buffer(str));
+
+	return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
+}
 
 /*! \brief Send SIP INFO dtmf message, see Cisco documentation on cisco.com */
 static int transmit_info_with_digit(struct sip_pvt *p, const char digit, unsigned int duration)
@@ -13979,6 +14042,7 @@
 	/* Take the peer */
 	ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+	ast_copy_flags(&p->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY);
 
 	if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && p->udptl) {
 		p->t38_maxdatagram = peer->t38_maxdatagram;
@@ -14023,6 +14087,7 @@
 	if (!(res = check_auth(p, req, peer->name, p->peersecret, p->peermd5secret, sipmethod, uri2, reliable, req->ignore))) {
 		ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
 		ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+		ast_copy_flags(&p->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY);
 		/* If we have a call limit, set flag */
 		if (peer->call_limit)
 			ast_set_flag(&p->flags[0], SIP_CALL_LIMIT);
@@ -23850,6 +23915,7 @@
 	copy_socket_data(&p->socket, &peer->socket);
 	ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+	ast_copy_flags(&p->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY);
 
 	/* Send OPTIONs to peer's fullcontact */
 	if (!ast_strlen_zero(peer->fullcontact))
@@ -24554,6 +24620,7 @@
 	peer->type = SIP_TYPE_PEER;
 	ast_copy_flags(&peer->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&peer->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+	ast_copy_flags(&peer->flags[2], &global_flags[2], SIP_PAGE3_FLAGS_TO_COPY);
 	ast_string_field_set(peer, context, sip_cfg.default_context);
 	ast_string_field_set(peer, subscribecontext, sip_cfg.default_subscribecontext);
 	ast_string_field_set(peer, language, default_language);
@@ -24658,8 +24725,8 @@
 	int format = 0;		/* Ama flags */
 	int timerb_set = 0, timert1_set = 0;
 	time_t regseconds = 0;
-	struct ast_flags peerflags[2] = {{(0)}};
-	struct ast_flags mask[2] = {{(0)}};
+	struct ast_flags peerflags[3] = {{(0)}};
+	struct ast_flags mask[3] = {{(0)}};
 	char callback[256] = "";
 	struct sip_peer tmp_peer;
 	const char *srvlookup = NULL;
@@ -25026,6 +25093,8 @@
 				ast_string_field_set(peer, unsolicited_mailbox, v->value);
 			} else if (!strcasecmp(v->name, "use_q850_reason")) {
 				ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_Q850_REASON);
+			} else if (!strcasecmp(v->name, "snom_aoc_enabled")) {
+				ast_set2_flag(&peer->flags[2], ast_true(v->value), SIP_PAGE3_SNOM_AOC);
 			}
 		}
 
@@ -25195,6 +25264,7 @@
 
 	ast_copy_flags(&peer->flags[0], &peerflags[0], mask[0].flags);
 	ast_copy_flags(&peer->flags[1], &peerflags[1], mask[1].flags);
+	ast_copy_flags(&peer->flags[2], &peerflags[2], mask[2].flags);
 	if (ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE)) {
 		sip_cfg.allowsubscribe = TRUE;	/* No global ban any more */
 	}
@@ -25923,6 +25993,8 @@
 			}
 		} else if (!strcasecmp(v->name, "use_q850_reason")) {
 			ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_Q850_REASON);
+		} else if (!strcasecmp(v->name, "snom_aoc_enabled")) {
+				ast_set2_flag(&global_flags[2], ast_true(v->value), SIP_PAGE3_SNOM_AOC);
 		}
 	}
 

Modified: team/dvossel/generic_aoc/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/generic_aoc/channels/sip/include/sip.h?view=diff&rev=252648&r1=252647&r2=252648
==============================================================================
--- team/dvossel/generic_aoc/channels/sip/include/sip.h (original)
+++ team/dvossel/generic_aoc/channels/sip/include/sip.h Mon Mar 15 17:21:42 2010
@@ -348,6 +348,12 @@
 	SIP_PAGE2_UDPTL_DESTINATION | SIP_PAGE2_VIDEOSUPPORT_ALWAYS | SIP_PAGE2_PREFERRED_CODEC | \
 	SIP_PAGE2_RPID_IMMEDIATE | SIP_PAGE2_RPID_UPDATE | SIP_PAGE2_SYMMETRICRTP |\
 	SIP_PAGE2_Q850_REASON)
+
+
+#define SIP_PAGE3_SNOM_AOC               (1 << 0)  /*!< DPG: Allow snom aoc messages */
+
+#define SIP_PAGE3_FLAGS_TO_COPY \
+	(SIP_PAGE3_SNOM_AOC)
 
 /*@}*/
 
@@ -937,7 +943,7 @@
 	ast_group_t callgroup;                  /*!< Call group */
 	ast_group_t pickupgroup;                /*!< Pickup group */
 	int lastinvite;                         /*!< Last Cseq of invite */
-	struct ast_flags flags[2];              /*!< SIP_ flags */
+	struct ast_flags flags[3];              /*!< SIP_ flags */
 
 	/* boolean flags that don't belong in flags */
 	unsigned short do_history:1;          /*!< Set if we want to record history */
@@ -1163,7 +1169,7 @@
 	struct ast_codec_pref prefs;    /*!<  codec prefs */
 	int lastmsgssent;
 	unsigned int sipoptions;        /*!<  Supported SIP options */
-	struct ast_flags flags[2];      /*!<  SIP_ flags */
+	struct ast_flags flags[3];      /*!<  SIP_ flags */
 
 	/*! Mailboxes that this peer cares about */
 	AST_LIST_HEAD_NOLOCK(, sip_mailbox) mailboxes;

Modified: team/dvossel/generic_aoc/configs/sip.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/generic_aoc/configs/sip.conf.sample?view=diff&rev=252648&r1=252647&r2=252648
==============================================================================
--- team/dvossel/generic_aoc/configs/sip.conf.sample (original)
+++ team/dvossel/generic_aoc/configs/sip.conf.sample Mon Mar 15 17:21:42 2010
@@ -866,6 +866,12 @@
                                 ; it may be a mandatory requirement for some
                                 ; destinations which do not have a prior
                                 ; account relationship with your server.
+
+;------------------------------ Advice of Charge CONFIGURATION --------------------------
+; snom_aoc_enabled = yes;     ; This options turns on and off support for sending AOC-D and
+                              ; AOC-E to snom endpoints.  This option can be used both in the
+							  ; peer and global scope.  The default for this option is off.
+
 
 ;------------------------------ JITTER BUFFER CONFIGURATION --------------------------
 ; jbenable = yes              ; Enables the use of a jitterbuffer on the receiving side of a

Modified: team/dvossel/generic_aoc/include/asterisk/frame.h
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/generic_aoc/include/asterisk/frame.h?view=diff&rev=252648&r1=252647&r2=252648
==============================================================================
--- team/dvossel/generic_aoc/include/asterisk/frame.h (original)
+++ team/dvossel/generic_aoc/include/asterisk/frame.h Mon Mar 15 17:21:42 2010
@@ -326,6 +326,7 @@
 	AST_CONTROL_T38_PARAMETERS = 24, /*! T38 state change request/notification with parameters */
 	AST_CONTROL_CC = 25, /*!< Indication that Call completion service is possible */
 	AST_CONTROL_SRCCHANGE = 26,  /*!< Media source has changed and requires a new RTP SSRC */
+	AST_CONTROL_AOC = 27,           /*!< Advice of Charge with encoded generic AOC payload */
 };
 
 enum ast_control_t38 {

Modified: team/dvossel/generic_aoc/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/generic_aoc/main/channel.c?view=diff&rev=252648&r1=252647&r2=252648
==============================================================================
--- team/dvossel/generic_aoc/main/channel.c (original)
+++ team/dvossel/generic_aoc/main/channel.c Mon Mar 15 17:21:42 2010
@@ -3617,6 +3617,7 @@
 	case AST_CONTROL_T38_PARAMETERS:
 	case _XXX_AST_CONTROL_T38:
 	case AST_CONTROL_CC:
+	case AST_CONTROL_AOC:
 		break;
 
 	case AST_CONTROL_CONGESTION:
@@ -3760,6 +3761,7 @@
 	case AST_CONTROL_CONNECTED_LINE:
 	case AST_CONTROL_REDIRECTING:
 	case AST_CONTROL_CC:
+	case AST_CONTROL_AOC:
 		/* Nothing left to do for these. */
 		res = 0;
 		break;

Modified: team/dvossel/generic_aoc/main/manager.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/generic_aoc/main/manager.c?view=diff&rev=252648&r1=252647&r2=252648
==============================================================================
--- team/dvossel/generic_aoc/main/manager.c (original)
+++ team/dvossel/generic_aoc/main/manager.c Mon Mar 15 17:21:42 2010
@@ -74,6 +74,7 @@
 #include "asterisk/astobj2.h"
 #include "asterisk/features.h"
 #include "asterisk/security_events.h"
+#include "asterisk/aoc.h"
 
 /*** DOCUMENTATION
 	<manager name="Ping" language="en_US">
@@ -692,6 +693,114 @@
 		<description>
 			<para>Checks if Asterisk module is loaded. Will return Success/Failure.
 			For success returns, the module revision number is included.</para>
+		</description>
+	</manager>
+	<manager name="AOCMessage" language="en_US">
+		<synopsis>
+			Generate an Advice of Charge message on a channel.
+		</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+			<parameter name="Channel" required="true">
+				<para>Channel name to generate the AOC message on.</para>
+			</parameter>
+			<parameter name="ChannelPrefix">
+				<para>Partial channel prefix.  By using this option one can match the beginning part
+				of a channel name without having to put the entire name in.  For example 
+				if a channel name is SIP/snom-00000001 and this value is set to SIP/snom, then
+				that channel matches and the message will be sent.  Note however that only
+				the first matched channel has the message sent on it. </para>
+			</parameter>
+			<parameter name="MsgType" required="true">
+				<para>Defines what time of AOC message to create, ACO-D or AOC-E</para>
+				<enumlist>
+					<enum name="D" />
+					<enum name="E" />
+				</enumlist>
+			</parameter>
+			<parameter name="ChargeType" required="true">
+				<para>Defines what kind of charge this message represents.</para>
+				<enumlist>
+					<enum name="NA" />
+					<enum name="FREE" />
+					<enum name="Currency" />
+					<enum name="Unit" />
+				</enumlist>
+			</parameter>
+			<parameter name="UnitAmount(0)">
+				<para>This represents the amount of units charged. The ETSI AOC standard specifies that
+				this value along with the optional UnitType value are entries in a list.  To accommodate this
+				these values take an index value starting at 0 which can be used to generate this list of
+				unit entries.  For Example, If two unit entires were required this could be achieved by setting the
+				paramter UnitAmount(0)=1234 and UnitAmount(1)=5678.  Note that UnitAmount at index 0 is
+				required when ChargeType=Unit, all other entries in the list are optional.
+				</para>
+			</parameter>
+			<parameter name="UnitType(0)">
+				<para>Defines the type of unit.  ETSI AOC standard specifies this as an integer
+				value between 1 and 16, but this value is left open to accept any positive
+				integer.  Like the UnitAmount parameter, this value represents a list entry
+				and has an index parameter that starts at 0.
+				</para>
+			</parameter>
+			<parameter name="CurrencyName">
+				<para>Specifies the currency's name.  Note that this value is truncated after 10 characters.</para>
+			</parameter>
+			<parameter name="CurrencyAmount">
+				<para>Specifies the charge unit amount as a positive integer.  This value is required
+				when ChargeType==Currency.</para>
+			</parameter>
+			<parameter name="CurrencyMultiplier">
+				<para>Specifies the currency multiplier.  This value is required when ChargeType==Currency.</para>
+				<enumlist>
+					<enum name="OneThousandth" />
+					<enum name="OneHundredth" />
+					<enum name="OneTenth" />
+					<enum name="One" />
+					<enum name="Ten" />
+					<enum name="Hundred" />
+					<enum name="Thousand" />
+				</enumlist>
+			</parameter>
+			<parameter name="TotalType" default="Total">
+				<para>Defines what kind of AOC-D total is represented.</para>
+				<enumlist>
+					<enum name="Total" />
+					<enum name="SubTotal" />
+				</enumlist>
+			</parameter>
+			<parameter name="AOCDBillingId">
+				<para>Represents a billing id associated with a AOC-D message.</para>
+				<enumlist>
+					<enum name="Normal" />
+					<enum name="ReverseCharge" />
+					<enum name="CreditCard" />
+				</enumlist>
+			</parameter>
+			<parameter name="AOCEBillingId">
+				<para>Represents a billing id associated with a AOC-E message.</para>
+				<enumlist>
+					<enum name="Normal" />
+					<enum name="ReverseCharge" />
+					<enum name="CreditCard" />
+					<enum name="CallFwdUnconditional" />
+					<enum name="CallFwdBusy" />
+					<enum name="CallFwdNoReply" />
+					<enum name="CallDeflection" />
+					<enum name="CallTransfer" />
+				</enumlist>
+			</parameter>
+			<parameter name="ChargingAssociationId">
+				<para>Charging association identifier.  This is optional for AOC-E and can be
+				set to any value between -32768 and 32767</para>
+			</parameter>
+			<parameter name="ChargingAssociationNumber">
+				<para>Represents the charging association party number.  This value is optional
+				for AOC-E.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Generates an AOC-D or AOC-E message on a channel.</para>
 		</description>
 	</manager>
  ***/
@@ -3374,6 +3483,228 @@
 	return NULL;
 }
 
+static int aocmessage_get_unit_entry(const struct message *m, struct ast_aoc_unit_entry *entry, unsigned int entry_num)
+{
+	const char *unitamount;
+	const char *unittype;
+	struct ast_str *str = ast_str_alloca(32);
+
+	memset(entry, 0, sizeof(*entry));
+
+	ast_str_set(&str, 0, "UnitAmount(%u)", entry_num);
+	unitamount = astman_get_header(m, ast_str_buffer(str));
+
+	ast_str_set(&str, 0, "UnitType(%u)", entry_num);
+	unittype = astman_get_header(m, ast_str_buffer(str));
+
+	/* unit amount is required, so we can't have a type without a amount */
+	if (ast_strlen_zero(unitamount) || (sscanf(unitamount, "%30u", &entry->amount) != 1)) {
+		return -1;
+	}
+
+	if (!ast_strlen_zero(unittype)) {
+		sscanf(unittype, "%30u", &entry->type);
+	}
+
+
+	return 0;
+}
+
+static int action_aocmessage(struct mansession *s, const struct message *m)
+{
+	const char *channel = astman_get_header(m, "Channel");
+	const char *pchannel = astman_get_header(m, "ChannelPrefix");
+	const char *msgtype = astman_get_header(m, "MsgType");
+	const char *chargetype = astman_get_header(m, "ChargeType");
+	const char *currencyname = astman_get_header(m, "CurrencyName");
+	const char *currencyamount = astman_get_header(m, "CurrencyAmount");
+	const char *mult = astman_get_header(m, "CurrencyMultiplier");
+	const char *totaltype = astman_get_header(m, "TotalType");
+	const char *aocebillingid = astman_get_header(m, "AOCEBillingId");
+	const char *aocdbillingid = astman_get_header(m, "AOCDBillingId");
+	const char *association_id= astman_get_header(m, "ChargingAssociationId");
+	const char *association_num = astman_get_header(m, "ChargingAssociationNumber");
+
+	enum ast_aoc_type _msgtype;
+	enum ast_aoc_charge_type _chargetype;
+	enum ast_aoc_currency_multiplier _mult = AST_AOC_MULT_ONE;
+	enum ast_aoc_total_type _totaltype = AOC_TOTAL;
+	enum ast_aoc_billing_id _billingid = AST_AOC_BILLING_NA;
+	unsigned int _currencyamount = 0;
+	int _association_id = 0;
+	struct ast_channel *chan = NULL;
+
+	struct ast_aoc_decoded *decoded = NULL;
+	struct ast_aoc_encoded *encoded = NULL;
+	size_t encoded_size = 0;
+
+	if (ast_strlen_zero(channel) && ast_strlen_zero(pchannel)) {
+		astman_send_error(s, m, "Channel and PartialChannel are not specified. Specify at least one of these.");
+		goto aocmessage_cleanup;
+	}
+
+	if (!(chan = ast_channel_get_by_name(channel)) && !ast_strlen_zero(pchannel)) {
+		chan = ast_channel_get_by_name_prefix(pchannel, strlen(pchannel));
+	}
+
+	if (!chan) {
+		astman_send_error(s, m, "No such channel");
+		goto aocmessage_cleanup;
+	}
+
+	if (ast_strlen_zero(msgtype) || (strcasecmp(msgtype, "d") && strcasecmp(msgtype, "e"))) {
+		astman_send_error(s, m, "Invalid MsgType");
+		goto aocmessage_cleanup;
+	}
+
+	if (ast_strlen_zero(chargetype)) {
+		astman_send_error(s, m, "ChargeType not specified");
+		goto aocmessage_cleanup;
+	}
+
+	_msgtype = strcasecmp(msgtype, "d") ? AOC_E : AOC_D;
+
+	if (!strcasecmp(chargetype, "NA")) {
+		_chargetype = AOC_CHARGE_NA;
+	} else if (!strcasecmp(chargetype, "Free")) {
+		_chargetype = AOC_CHARGE_FREE;
+	} else if (!strcasecmp(chargetype, "Currency")) {
+		_chargetype = AOC_CHARGE_CURRENCY;
+	} else if (!strcasecmp(chargetype, "Unit")) {
+		_chargetype = AOC_CHARGE_UNIT;
+	} else {
+		astman_send_error(s, m, "Invalid ChargeType");
+		goto aocmessage_cleanup;
+	}
+
+	if (_chargetype == AOC_CHARGE_CURRENCY) {
+
+		if (ast_strlen_zero(currencyamount) || (sscanf(currencyamount, "%30u", &_currencyamount) != 1)) {
+			astman_send_error(s, m, "Invalid CurrencyAmount, CurrencyAmount is a required when ChargeType is Currency");
+		}
+
+		if (ast_strlen_zero(mult)) {
+			astman_send_error(s, m, "ChargeMultiplier unspecified, ChargeMultiplier is required when ChargeType is Currency.");
+			goto aocmessage_cleanup;
+		} else if (!strcasecmp(mult, "onethousandth")) {
+			_mult = AST_AOC_MULT_ONETHOUSANDTH;
+		} else if (!strcasecmp(mult, "onehundredth")) {
+			_mult = AST_AOC_MULT_ONEHUNDREDTH;
+		} else if (!strcasecmp(mult, "onetenth")) {
+			_mult = AST_AOC_MULT_ONETENTH;
+		} else if (!strcasecmp(mult, "one")) {
+			_mult = AST_AOC_MULT_ONE;
+		} else if (!strcasecmp(mult, "ten")) {
+			_mult = AST_AOC_MULT_TEN;
+		} else if (!strcasecmp(mult, "hundred")) {
+			_mult = AST_AOC_MULT_HUNDRED;
+		} else if (!strcasecmp(mult, "thousand")) {
+			_mult = AST_AOC_MULT_THOUSAND;
+		} else {
+			astman_send_error(s, m, "Invalid ChargeMultiplier");
+			goto aocmessage_cleanup;
+		}
+	}
+
+	if (_msgtype == AOC_D) {
+		if (!ast_strlen_zero(totaltype) && !strcasecmp(totaltype, "subtotal")) {
+			_totaltype = AOC_SUBTOTAL;
+		}
+
+		if (ast_strlen_zero(aocdbillingid)) {
+			/* ignore this is optional */
+		} else if (!strcasecmp(aocdbillingid, "Normal")) {
+			_billingid = AST_AOC_BILLING_NORMAL;
+		} else if (!strcasecmp(aocdbillingid, "ReverseCharge")) {
+			_billingid = AST_AOC_BILLING_REVERSE_CHARGE;
+		} else if (!strcasecmp(aocdbillingid, "CreditCard")) {
+			_billingid = AST_AOC_BILLING_CREDIT_CARD;
+		} else {
+			astman_send_error(s, m, "Invalid AOCDBillingId");
+			goto aocmessage_cleanup;
+		}
+	} else {
+		if (ast_strlen_zero(aocebillingid)) {
+			/* ignore this is optional */
+		} else if (!strcasecmp(aocebillingid, "Normal")) {
+			_billingid = AST_AOC_BILLING_NORMAL;
+		} else if (!strcasecmp(aocebillingid, "ReverseCharge")) {
+			_billingid = AST_AOC_BILLING_REVERSE_CHARGE;
+		} else if (!strcasecmp(aocebillingid, "CreditCard")) {
+			_billingid = AST_AOC_BILLING_CREDIT_CARD;
+		} else if (!strcasecmp(aocebillingid, "CallFwdUnconditional")) {
+			_billingid = AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL;
+		} else if (!strcasecmp(aocebillingid, "CallFwdBusy")) {
+			_billingid = AST_AOC_BILLING_CALL_FWD_BUSY;
+		} else if (!strcasecmp(aocebillingid, "CallFwdNoReply")) {
+			_billingid = AST_AOC_BILLING_CALL_FWD_NO_REPLY;
+		} else if (!strcasecmp(aocebillingid, "CallDeflection")) {
+			_billingid = AST_AOC_BILLING_CALL_DEFLECTION;
+		} else if (!strcasecmp(aocebillingid, "CallTransfer")) {
+			_billingid = AST_AOC_BILLING_CALL_TRANSFER;
+		} else {
+			astman_send_error(s, m, "Invalid AOCEBillingId");
+			goto aocmessage_cleanup;
+		}
+
+		if (!ast_strlen_zero(association_id) && (sscanf(association_id, "%30d", &_association_id) != 1)) {
+			astman_send_error(s, m, "Invalid ChargingAssociationId");
+		}
+
+	}
+
+	/* create decoded object and start setting values */
+	if (!(decoded = ast_aoc_create(_msgtype, _chargetype, 0))) {
+			astman_send_error(s, m, "Message Creation Failed");
+			goto aocmessage_cleanup;
+	}
+
+	if (_chargetype == AOC_CHARGE_CURRENCY) {
+		ast_aoc_set_currency_info(decoded, _currencyamount, _mult, ast_strlen_zero(currencyname) ? NULL : currencyname);
+	} else if (_chargetype == AOC_CHARGE_UNIT) {
+		struct ast_aoc_unit_entry entry;
+		int i;
+
+		/* multiple unit entries are possible, lets get them all */
+		for (i = 0; i < 32; i++) {
+			if (aocmessage_get_unit_entry(m, &entry, i)) {
+				break; /* that's the end then */
+			}
+
+			ast_aoc_add_unit_entry(decoded, entry.amount, entry.type);
+		}
+
+		/* at least one unit entry is required */
+		if (!i) {
+			astman_send_error(s, m, "Invalid UnitAmount(0), At least one valid unit entry is required when ChargeType is set to Unit");
+			goto aocmessage_cleanup;
+		}
+
+	}
+
+	ast_aoc_set_association_number(decoded, association_num);
+	ast_aoc_set_association_id(decoded, _association_id);
+	ast_aoc_set_billing_id(decoded, _billingid);
+	ast_aoc_set_total_type(decoded, _totaltype);
+
+
+	if ((encoded = ast_aoc_encode(decoded, &encoded_size)) && !ast_indicate_data(chan, AST_CONTROL_AOC, encoded, encoded_size)) {
+		astman_send_ack(s, m, "AOC Message successfully queued on channel");
+	} else {
+		astman_send_error(s, m, "Error encoding AOC message, could not queue onto channel");
+	}
+
+aocmessage_cleanup:
+
+	ast_aoc_destroy_decoded(decoded);
+	ast_aoc_destroy_encoded(encoded);
+
+	if (chan) {
+		chan = ast_channel_unref(chan);
+	}
+	return 0;
+}
+
 static int action_originate(struct mansession *s, const struct message *m)
 {
 	const char *name = astman_get_header(m, "Channel");
@@ -5586,6 +5917,7 @@
 		ast_manager_register_xml("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels);
 		ast_manager_register_xml("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
 		ast_manager_register_xml("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
+		ast_manager_register_xml("AOCMessage", EVENT_FLAG_CALL, action_aocmessage);
 
 		ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
 		ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);




More information about the svn-commits mailing list