]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
manager: AOC-S support for AOCMessage
authorMichael Kuron <m.kuron@gmx.de>
Tue, 1 Nov 2022 20:37:30 +0000 (21:37 +0100)
committerFriendly Automation <jenkins2@gerrit.asterisk.org>
Fri, 9 Dec 2022 13:59:21 +0000 (07:59 -0600)
ASTERISK-21502

Change-Id: I051b778f8c862d3b4794d28f2f3d782316707b08

doc/CHANGES-staging/manager_aoc.txt [new file with mode: 0644]
main/manager.c

diff --git a/doc/CHANGES-staging/manager_aoc.txt b/doc/CHANGES-staging/manager_aoc.txt
new file mode 100644 (file)
index 0000000..ed90cf6
--- /dev/null
@@ -0,0 +1,3 @@
+Subject: AMI
+
+The AOCMessage action can now be used to generate AOC-S messages.
index fc65a33ca4ad26d6def06e4e45dfac88c8983584..8a198b38ac9b0ba14dbd1666aaa03ae0fda89916 100644 (file)
                </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 name="Channel">
+                               <para>Channel name to generate the AOC message on.
+                               This value is required unless ChannelPrefix is given.</para>
                        </parameter>
                        <parameter name="ChannelPrefix">
                                <para>Partial channel prefix.  By using this option one can match the beginning part
                                the first matched channel has the message sent on it. </para>
                        </parameter>
                        <parameter name="MsgType" required="true">
-                               <para>Defines what type of AOC message to create, AOC-D or AOC-E</para>
+                               <para>Defines what type of AOC message to create, AOC-S, AOC-D or AOC-E</para>
                                <enumlist>
+                                       <enum name="S" />
                                        <enum name="D" />
                                        <enum name="E" />
                                </enumlist>
                        </parameter>
-                       <parameter name="ChargeType" required="true">
-                               <para>Defines what kind of charge this message represents.</para>
+                       <parameter name="ChargeType">
+                               <para>Defines what kind of charge this message represents for AOC-D and AOC-E.</para>
                                <enumlist>
                                        <enum name="NA" />
                                        <enum name="FREE" />
                                <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>
+                               <para>Specifies the charge unit amount as a positive integer.
+                               This value is required when ChargeType==Currency (AOC-D or AOC-E) or
+                               RateType==Duration/Flat/Volume (AOC-S).</para>
                        </parameter>
                        <parameter name="CurrencyMultiplier">
-                               <para>Specifies the currency multiplier.  This value is required when ChargeType==Currency.</para>
+                               <para>Specifies the currency multiplier.
+                               This value is required when CurrencyAmount is given.</para>
                                <enumlist>
                                        <enum name="OneThousandth" />
                                        <enum name="OneHundredth" />
                                The value is bits 7 through 1 of the Q.931 octet containing the type-of-number and
                                numbering-plan-identification fields.</para>
                        </parameter>
+                       <parameter name="ChargedItem">
+                               <para>Defines what part of the call is charged in AOC-S. Usually this is set to
+                               BasicCommunication, which refers to the time after the call is answered, but establishment
+                               (CallAttempt) or successful establishment (CallSetup) of a call can also be used.
+                               Other options are available, but these generally do not carry enough information to actually
+                               calculate the price of a call.
+                               It is possible to have multiple ChargedItem entries for a single call -- for example to
+                               charge for both the establishment of the call and the actual call. In this case, each
+                               ChargedItem is described by a ChargedItem: header and all other headers that follow it up to
+                               the next ChargedItem: header.</para>
+                               <enumlist>
+                                       <enum name="NA" />
+                                       <enum name="SpecialArrangement" />
+                                       <enum name="BasicCommunication" />
+                                       <enum name="CallAttempt" />
+                                       <enum name="CallSetup" />
+                                       <enum name="UserUserInfo" />
+                                       <enum name="SupplementaryService" />
+                               </enumlist>
+                       </parameter>
+                       <parameter name="RateType">
+                               <para>Defines how an AOC-S ChargedItem is charged.
+                               The Duration option is only available when ChargedItem==BasicCommunication.</para>
+                               <enumlist>
+                                       <enum name="NA" />
+                                       <enum name="Free" />
+                                       <enum name="FreeFromBeginning" />
+                                       <enum name="Duration" />
+                                       <enum name="Flat" />
+                                       <enum name="Volume" />
+                                       <enum name="SpecialCode" />
+                               </enumlist>
+                       </parameter>
+                       <parameter name="Time">
+                               <para>Specifies a positive integer which is the amount of time is paid for by one
+                               CurrencyAmount.
+                               This value is required when RateType==Duration.</para>
+                       </parameter>
+                       <parameter name="TimeScale">
+                               <para>Specifies the time multiplier.
+                               This value is required when Time is given.</para>
+                               <enumlist>
+                                       <enum name="OneHundredthSecond" />
+                                       <enum name="OneTenthSecond" />
+                                       <enum name="Second" />
+                                       <enum name="TenSeconds" />
+                                       <enum name="Minute" />
+                                       <enum name="Hour" />
+                                       <enum name="Day" />
+                               </enumlist>
+                       </parameter>
+                       <parameter name="Granularity">
+                               <para>Specifies a positive integer which is the size of the charged time increments.
+                               This value is optional when RateType==Duration and ChargingType==StepFunction.</para>
+                       </parameter>
+                       <parameter name="GranularityTimeScale">
+                               <para>Specifies the granularity time multiplier.
+                               This value is required when Granularity is given.</para>
+                               <enumlist>
+                                       <enum name="OneHundredthSecond" />
+                                       <enum name="OneTenthSecond" />
+                                       <enum name="Second" />
+                                       <enum name="TenSeconds" />
+                                       <enum name="Minute" />
+                                       <enum name="Hour" />
+                                       <enum name="Day" />
+                               </enumlist>
+                       </parameter>
+                       <parameter name="ChargingType">
+                               <para>Specifies whether the charge increases continuously with time or in increments of
+                               Time or, if provided, Granularity.
+                               This value is required when RateType==Duration.</para>
+                               <enumlist>
+                                       <enum name="ContinuousCharging" />
+                                       <enum name="StepFunction" />
+                               </enumlist>
+                       </parameter>
+                       <parameter name="VolumeUnit">
+                               <para>Specifies the quantity of which one unit is paid for by one CurrencyAmount.
+                               This value is required when RateType==Volume.</para>
+                               <enumlist>
+                                       <enum name="Octet" />
+                                       <enum name="Segment" />
+                                       <enum name="Message" />
+                               </enumlist>
+                       </parameter>
+                       <parameter name="Code">
+                               <para>Specifies the charging code, which can be set to a value between 1 and 10.
+                               This value is required when ChargedItem==SpecialArrangement or RateType==SpecialCode.</para>
+                       </parameter>
                </syntax>
                <description>
-                       <para>Generates an AOC-D or AOC-E message on a channel.</para>
+                       <para>Generates an AOC-S, AOC-D or AOC-E message on a channel.</para>
                </description>
                <see-also>
+                       <ref type="managerEvent">AOC-S</ref>
                        <ref type="managerEvent">AOC-D</ref>
                        <ref type="managerEvent">AOC-E</ref>
                </see-also>
@@ -5549,10 +5644,8 @@ static int aocmessage_get_unit_entry(const struct message *m, struct ast_aoc_uni
        return 0;
 }
 
-static int action_aocmessage(struct mansession *s, const struct message *m)
+static struct ast_aoc_decoded *action_aoc_de_message(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");
@@ -5572,30 +5665,8 @@ static int action_aocmessage(struct mansession *s, const struct message *m)
        unsigned int _currencyamount = 0;
        int _association_id = 0;
        unsigned int _association_plan = 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");
@@ -5736,8 +5807,324 @@ static int action_aocmessage(struct mansession *s, const struct message *m)
        ast_aoc_set_billing_id(decoded, _billingid);
        ast_aoc_set_total_type(decoded, _totaltype);
 
+       return decoded;
+
+aocmessage_cleanup:
+
+       ast_aoc_destroy_decoded(decoded);
+       return NULL;
+}
+
+static int action_aoc_s_submessage(struct mansession *s, const struct message *m,
+               struct ast_aoc_decoded *decoded)
+{
+       const char *chargeditem = __astman_get_header(m, "ChargedItem", GET_HEADER_LAST_MATCH);
+       const char *ratetype = __astman_get_header(m, "RateType", GET_HEADER_LAST_MATCH);
+       const char *currencyname = __astman_get_header(m, "CurrencyName", GET_HEADER_LAST_MATCH);
+       const char *currencyamount = __astman_get_header(m, "CurrencyAmount", GET_HEADER_LAST_MATCH);
+       const char *mult = __astman_get_header(m, "CurrencyMultiplier", GET_HEADER_LAST_MATCH);
+       const char *time = __astman_get_header(m, "Time", GET_HEADER_LAST_MATCH);
+       const char *timescale = __astman_get_header(m, "TimeScale", GET_HEADER_LAST_MATCH);
+       const char *granularity = __astman_get_header(m, "Granularity", GET_HEADER_LAST_MATCH);
+       const char *granularitytimescale = __astman_get_header(m, "GranularityTimeScale", GET_HEADER_LAST_MATCH);
+       const char *chargingtype = __astman_get_header(m, "ChargingType", GET_HEADER_LAST_MATCH);
+       const char *volumeunit = __astman_get_header(m, "VolumeUnit", GET_HEADER_LAST_MATCH);
+       const char *code = __astman_get_header(m, "Code", GET_HEADER_LAST_MATCH);
+
+       enum ast_aoc_s_charged_item _chargeditem;
+       enum ast_aoc_s_rate_type _ratetype;
+       enum ast_aoc_currency_multiplier _mult = AST_AOC_MULT_ONE;
+       unsigned int _currencyamount = 0;
+       unsigned int _code;
+       unsigned int _time = 0;
+       enum ast_aoc_time_scale _scale = 0;
+       unsigned int _granularity = 0;
+       enum ast_aoc_time_scale _granularity_time_scale = AST_AOC_TIME_SCALE_MINUTE;
+       int _step = 0;
+       enum ast_aoc_volume_unit _volumeunit = 0;
+
+       if (ast_strlen_zero(chargeditem)) {
+               astman_send_error(s, m, "ChargedItem not specified");
+               goto aocmessage_cleanup;
+       }
+
+       if (ast_strlen_zero(ratetype)) {
+               astman_send_error(s, m, "RateType not specified");
+               goto aocmessage_cleanup;
+       }
+
+       if (!strcasecmp(chargeditem, "NA")) {
+               _chargeditem = AST_AOC_CHARGED_ITEM_NA;
+       } else if (!strcasecmp(chargeditem, "SpecialArrangement")) {
+               _chargeditem = AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
+       } else if (!strcasecmp(chargeditem, "BasicCommunication")) {
+               _chargeditem = AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION;
+       } else if (!strcasecmp(chargeditem, "CallAttempt")) {
+               _chargeditem = AST_AOC_CHARGED_ITEM_CALL_ATTEMPT;
+       } else if (!strcasecmp(chargeditem, "CallSetup")) {
+               _chargeditem = AST_AOC_CHARGED_ITEM_CALL_SETUP;
+       } else if (!strcasecmp(chargeditem, "UserUserInfo")) {
+               _chargeditem = AST_AOC_CHARGED_ITEM_USER_USER_INFO;
+       } else if (!strcasecmp(chargeditem, "SupplementaryService")) {
+               _chargeditem = AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE;
+       } else {
+               astman_send_error(s, m, "Invalid ChargedItem");
+               goto aocmessage_cleanup;
+       }
+
+       if (!strcasecmp(ratetype, "NA")) {
+               _ratetype = AST_AOC_RATE_TYPE_NA;
+       } else if (!strcasecmp(ratetype, "Free")) {
+               _ratetype = AST_AOC_RATE_TYPE_FREE;
+       } else if (!strcasecmp(ratetype, "FreeFromBeginning")) {
+               _ratetype = AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING;
+       } else if (!strcasecmp(ratetype, "Duration")) {
+               _ratetype = AST_AOC_RATE_TYPE_DURATION;
+       } else if (!strcasecmp(ratetype, "Flat")) {
+               _ratetype = AST_AOC_RATE_TYPE_FLAT;
+       } else if (!strcasecmp(ratetype, "Volume")) {
+               _ratetype = AST_AOC_RATE_TYPE_VOLUME;
+       } else if (!strcasecmp(ratetype, "SpecialCode")) {
+               _ratetype = AST_AOC_RATE_TYPE_SPECIAL_CODE;
+       } else {
+               astman_send_error(s, m, "Invalid RateType");
+               goto aocmessage_cleanup;
+       }
+
+       if (_ratetype > AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING) {
+               if (ast_strlen_zero(currencyamount) || (sscanf(currencyamount, "%30u",
+                               &_currencyamount) != 1)) {
+                       astman_send_error(s, m, "Invalid CurrencyAmount, CurrencyAmount is a required when RateType is non-free");
+                       goto aocmessage_cleanup;
+               }
+
+               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 (_ratetype == AST_AOC_RATE_TYPE_DURATION) {
+               if (ast_strlen_zero(timescale)) {
+                       astman_send_error(s, m, "TimeScale unspecified, TimeScale is required when RateType is Duration.");
+                       goto aocmessage_cleanup;
+               } else if (!strcasecmp(timescale, "onehundredthsecond")) {
+                       _scale = AST_AOC_TIME_SCALE_HUNDREDTH_SECOND;
+               } else if (!strcasecmp(timescale, "onetenthsecond")) {
+                       _scale = AST_AOC_TIME_SCALE_TENTH_SECOND;
+               } else if (!strcasecmp(timescale, "second")) {
+                       _scale = AST_AOC_TIME_SCALE_SECOND;
+               } else if (!strcasecmp(timescale, "tenseconds")) {
+                       _scale = AST_AOC_TIME_SCALE_TEN_SECOND;
+               } else if (!strcasecmp(timescale, "minute")) {
+                       _scale = AST_AOC_TIME_SCALE_MINUTE;
+               } else if (!strcasecmp(timescale, "hour")) {
+                       _scale = AST_AOC_TIME_SCALE_HOUR;
+               } else if (!strcasecmp(timescale, "day")) {
+                       _scale = AST_AOC_TIME_SCALE_DAY;
+               } else {
+                       astman_send_error(s, m, "Invalid TimeScale");
+                       goto aocmessage_cleanup;
+               }
+
+               if (ast_strlen_zero(time) || (sscanf(time, "%30u", &_time) != 1)) {
+                       astman_send_error(s, m, "Invalid Time, Time is a required when RateType is Duration");
+                       goto aocmessage_cleanup;
+               }
+
+               if (!ast_strlen_zero(granularity)) {
+                       if ((sscanf(time, "%30u", &_granularity) != 1)) {
+                               astman_send_error(s, m, "Invalid Granularity");
+                               goto aocmessage_cleanup;
+                       }
+
+                       if (ast_strlen_zero(granularitytimescale)) {
+                               astman_send_error(s, m, "Invalid GranularityTimeScale, GranularityTimeScale is a required when Granularity is specified");
+                       } else if (!strcasecmp(granularitytimescale, "onehundredthsecond")) {
+                               _granularity_time_scale = AST_AOC_TIME_SCALE_HUNDREDTH_SECOND;
+                       } else if (!strcasecmp(granularitytimescale, "onetenthsecond")) {
+                               _granularity_time_scale = AST_AOC_TIME_SCALE_TENTH_SECOND;
+                       } else if (!strcasecmp(granularitytimescale, "second")) {
+                               _granularity_time_scale = AST_AOC_TIME_SCALE_SECOND;
+                       } else if (!strcasecmp(granularitytimescale, "tenseconds")) {
+                               _granularity_time_scale = AST_AOC_TIME_SCALE_TEN_SECOND;
+                       } else if (!strcasecmp(granularitytimescale, "minute")) {
+                               _granularity_time_scale = AST_AOC_TIME_SCALE_MINUTE;
+                       } else if (!strcasecmp(granularitytimescale, "hour")) {
+                               _granularity_time_scale = AST_AOC_TIME_SCALE_HOUR;
+                       } else if (!strcasecmp(granularitytimescale, "day")) {
+                               _granularity_time_scale = AST_AOC_TIME_SCALE_DAY;
+                       } else {
+                               astman_send_error(s, m, "Invalid GranularityTimeScale");
+                               goto aocmessage_cleanup;
+                       }
+               }
+
+               if (ast_strlen_zero(chargingtype) || strcasecmp(chargingtype, "continuouscharging") == 0) {
+                       _step = 0;
+               } else if (strcasecmp(chargingtype, "stepfunction") == 0 ) {
+                       _step = 1;
+               } else {
+                       astman_send_error(s, m, "Invalid ChargingType");
+                       goto aocmessage_cleanup;
+               }
+       }
+
+       if (_ratetype == AST_AOC_RATE_TYPE_VOLUME) {
+               if (ast_strlen_zero(volumeunit)) {
+                       astman_send_error(s, m, "VolumeUnit unspecified, VolumeUnit is required when RateType is Volume.");
+                       goto aocmessage_cleanup;
+               } else if (!strcasecmp(timescale, "octet")) {
+                       _volumeunit = AST_AOC_VOLUME_UNIT_OCTET;
+               } else if (!strcasecmp(timescale, "segment")) {
+                       _volumeunit = AST_AOC_VOLUME_UNIT_SEGMENT;
+               } else if (!strcasecmp(timescale, "message")) {
+                       _volumeunit = AST_AOC_VOLUME_UNIT_MESSAGE;
+               }else {
+                       astman_send_error(s, m, "Invalid VolumeUnit");
+                       goto aocmessage_cleanup;
+               }
+       }
+
+       if (_chargeditem == AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT
+                       || _ratetype == AST_AOC_RATE_TYPE_SPECIAL_CODE) {
+               if (ast_strlen_zero(code) || (sscanf(code, "%30u", &_code) != 1)) {
+                       astman_send_error(s, m, "Invalid Code, Code is a required when ChargedItem is SpecialArrangement and when RateType is SpecialCode");
+                       goto aocmessage_cleanup;
+               }
+       }
+
+       if (_chargeditem == AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT) {
+               ast_aoc_s_add_special_arrangement(decoded, _code);
+       } else if (_ratetype == AST_AOC_RATE_TYPE_DURATION) {
+               ast_aoc_s_add_rate_duration(decoded, _chargeditem, _currencyamount, _mult,
+                       currencyname, _time, _scale, _granularity, _granularity_time_scale, _step);
+       } else if (_ratetype == AST_AOC_RATE_TYPE_FLAT) {
+               ast_aoc_s_add_rate_flat(decoded, _chargeditem, _currencyamount, _mult,
+                               currencyname);
+       } else if (_ratetype == AST_AOC_RATE_TYPE_VOLUME) {
+               ast_aoc_s_add_rate_volume(decoded, _chargeditem, _volumeunit, _currencyamount,
+                       _mult, currencyname);
+       } else if (_ratetype == AST_AOC_RATE_TYPE_SPECIAL_CODE) {
+               ast_aoc_s_add_rate_special_charge_code(decoded, _chargeditem, _code);
+       } else if (_ratetype == AST_AOC_RATE_TYPE_FREE) {
+               ast_aoc_s_add_rate_free(decoded, _chargeditem, 0);
+       } else if (_ratetype == AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING) {
+               ast_aoc_s_add_rate_free(decoded, _chargeditem, 1);
+       } else if (_ratetype == AST_AOC_RATE_TYPE_NA) {
+               ast_aoc_s_add_rate_na(decoded, _chargeditem);
+       }
+
+       return 0;
+
+aocmessage_cleanup:
+
+       return -1;
+}
+
+static struct ast_aoc_decoded *action_aoc_s_message(struct mansession *s,
+               const struct message *m)
+{
+       struct ast_aoc_decoded *decoded = NULL;
+       int hdrlen;
+       int x;
+       static const char hdr[] = "ChargedItem:";
+       struct message sm = { 0 };
+       int rates = 0;
+
+       if (!(decoded = ast_aoc_create(AST_AOC_S, 0, 0))) {
+               astman_send_error(s, m, "Message Creation Failed");
+               goto aocmessage_cleanup;
+       }
+
+       hdrlen = strlen(hdr);
+       for (x = 0; x < m->hdrcount; x++) {
+               if (strncasecmp(hdr, m->headers[x], hdrlen) == 0) {
+                       if (rates > ast_aoc_s_get_count(decoded)) {
+                               if (action_aoc_s_submessage(s, &sm, decoded) == -1) {
+                                       goto aocmessage_cleanup;
+                               }
+                       }
+                       ++rates;
+               }
+
+               sm.headers[sm.hdrcount] = m->headers[x];
+               ++sm.hdrcount;
+       }
+       if (rates > ast_aoc_s_get_count(decoded)) {
+               if (action_aoc_s_submessage(s, &sm, decoded) == -1) {
+                       goto aocmessage_cleanup;
+               }
+       }
+
+       return decoded;
+
+aocmessage_cleanup:
+
+       ast_aoc_destroy_decoded(decoded);
+       return NULL;
+}
+
+static int action_aocmessage(struct mansession *s, const struct message *m)
+{
+       const char *msgtype = astman_get_header(m, "MsgType");
+       const char *channel = astman_get_header(m, "Channel");
+       const char *pchannel = astman_get_header(m, "ChannelPrefix");
+
+       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 (strcasecmp(msgtype, "d") == 0 || strcasecmp(msgtype, "e") == 0) {
+               decoded = action_aoc_de_message(s, m);
+       }
+       else if (strcasecmp(msgtype, "s") == 0) {
+               decoded = action_aoc_s_message(s, m);
+       }
+       else {
+               astman_send_error(s, m, "Invalid MsgType");
+               goto aocmessage_cleanup;
+       }
+
+       if (!decoded) {
+               goto aocmessage_cleanup;
+       }
 
-       if ((encoded = ast_aoc_encode(decoded, &encoded_size, NULL)) && !ast_indicate_data(chan, AST_CONTROL_AOC, encoded, encoded_size)) {
+       if ((encoded = ast_aoc_encode(decoded, &encoded_size, chan))
+                       && !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");