Merge "pbx: Reduce verbosity while loading extensions"
[asterisk/asterisk.git] / main / aoc.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2010, Digium, Inc.
5  *
6  * David Vossel <dvossel@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*!
20  * \file
21  * \brief generic AOC payload generation encoding and decoding
22  *
23  * \author David Vossel <dvossel@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 #include "asterisk/aoc.h"
33 #include "asterisk/utils.h"
34 #include "asterisk/strings.h"
35 #include "asterisk/_private.h"
36 #include "asterisk/cli.h"
37 #include "asterisk/manager.h"
38 #include "asterisk/stasis_channels.h"
39 #include "asterisk/stasis_message_router.h"
40
41 /*** DOCUMENTATION
42         <managerEvent language="en_US" name="AOC-S">
43                 <managerEventInstance class="EVENT_FLAG_AOC">
44                         <synopsis>Raised when an Advice of Charge message is sent at the beginning of a call.</synopsis>
45                         <syntax>
46                                 <channel_snapshot/>
47                                 <parameter name="Chargeable" />
48                                 <parameter name="RateType">
49                                         <enumlist>
50                                                 <enum name="NotAvailable" />
51                                                 <enum name="Free" />
52                                                 <enum name="FreeFromBeginning" />
53                                                 <enum name="Duration" />
54                                                 <enum name="Flag" />
55                                                 <enum name="Volume" />
56                                                 <enum name="SpecialCode" />
57                                         </enumlist>
58                                 </parameter>
59                                 <parameter name="Currency" />
60                                 <parameter name="Name" />
61                                 <parameter name="Cost" />
62                                 <parameter name="Multiplier">
63                                         <enumlist>
64                                                 <enum name="1/1000" />
65                                                 <enum name="1/100" />
66                                                 <enum name="1/10" />
67                                                 <enum name="1" />
68                                                 <enum name="10" />
69                                                 <enum name="100" />
70                                                 <enum name="1000" />
71                                         </enumlist>
72                                 </parameter>
73                                 <parameter name="ChargingType" />
74                                 <parameter name="StepFunction" />
75                                 <parameter name="Granularity" />
76                                 <parameter name="Length" />
77                                 <parameter name="Scale" />
78                                 <parameter name="Unit">
79                                         <enumlist>
80                                                 <enum name="Octect" />
81                                                 <enum name="Segment" />
82                                                 <enum name="Message" />
83                                         </enumlist>
84                                 </parameter>
85                                 <parameter name="SpecialCode" />
86                         </syntax>
87                         <see-also>
88                                 <ref type="managerEvent">AOC-D</ref>
89                                 <ref type="managerEvent">AOC-E</ref>
90                         </see-also>
91                 </managerEventInstance>
92         </managerEvent>
93         <managerEvent language="en_US" name="AOC-D">
94                 <managerEventInstance class="EVENT_FLAG_AOC">
95                         <synopsis>Raised when an Advice of Charge message is sent during a call.</synopsis>
96                         <syntax>
97                                 <channel_snapshot/>
98                                 <parameter name="Charge" />
99                                 <parameter name="Type">
100                                         <enumlist>
101                                                 <enum name="NotAvailable" />
102                                                 <enum name="Free" />
103                                                 <enum name="Currency" />
104                                                 <enum name="Units" />
105                                         </enumlist>
106                                 </parameter>
107                                 <parameter name="BillingID">
108                                         <enumlist>
109                                                 <enum name="Normal" />
110                                                 <enum name="Reverse" />
111                                                 <enum name="CreditCard" />
112                                                 <enum name="CallForwardingUnconditional" />
113                                                 <enum name="CallForwardingBusy" />
114                                                 <enum name="CallForwardingNoReply" />
115                                                 <enum name="CallDeflection" />
116                                                 <enum name="CallTransfer" />
117                                                 <enum name="NotAvailable" />
118                                         </enumlist>
119                                 </parameter>
120                                 <parameter name="TotalType">
121                                         <enumlist>
122                                                 <enum name="SubTotal" />
123                                                 <enum name="Total" />
124                                         </enumlist>
125                                 </parameter>
126                                 <parameter name="Currency" />
127                                 <parameter name="Name" />
128                                 <parameter name="Cost" />
129                                 <parameter name="Multiplier">
130                                         <enumlist>
131                                                 <enum name="1/1000" />
132                                                 <enum name="1/100" />
133                                                 <enum name="1/10" />
134                                                 <enum name="1" />
135                                                 <enum name="10" />
136                                                 <enum name="100" />
137                                                 <enum name="1000" />
138                                         </enumlist>
139                                 </parameter>
140                                 <parameter name="Units" />
141                                 <parameter name="NumberOf" />
142                                 <parameter name="TypeOf" />
143                         </syntax>
144                         <see-also>
145                                 <ref type="manager">AOCMessage</ref>
146                                 <ref type="managerEvent">AOC-S</ref>
147                                 <ref type="managerEvent">AOC-E</ref>
148                         </see-also>
149                 </managerEventInstance>
150         </managerEvent>
151         <managerEvent language="en_US" name="AOC-E">
152                 <managerEventInstance class="EVENT_FLAG_AOC">
153                         <synopsis>Raised when an Advice of Charge message is sent at the end of a call.</synopsis>
154                         <syntax>
155                                 <channel_snapshot/>
156                                 <parameter name="ChargingAssociation" />
157                                 <parameter name="Number" />
158                                 <parameter name="Plan" />
159                                 <parameter name="ID" />
160                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AOC-D']/managerEventInstance/syntax/parameter)" />
161                         </syntax>
162                         <see-also>
163                                 <ref type="manager">AOCMessage</ref>
164                                 <ref type="managerEvent">AOC-S</ref>
165                                 <ref type="managerEvent">AOC-D</ref>
166                         </see-also>
167                 </managerEventInstance>
168         </managerEvent>
169 ***/
170
171 /* Encoded Payload Flags */
172 #define AST_AOC_ENCODED_TYPE_REQUEST    (0 << 0)
173 #define AST_AOC_ENCODED_TYPE_D          (1 << 0)
174 #define AST_AOC_ENCODED_TYPE_E          (2 << 0)
175 #define AST_AOC_ENCODED_TYPE_S          (3 << 0)
176
177 #define AST_AOC_ENCODED_REQUEST_S       (1 << 2)
178 #define AST_AOC_ENCODED_REQUEST_D       (1 << 3)
179 #define AST_AOC_ENCODED_REQUEST_E       (1 << 4)
180
181 #define AST_AOC_ENCODED_CHARGE_NA       (0 << 5)
182 #define AST_AOC_ENCODED_CHARGE_FREE     (1 << 5)
183 #define AST_AOC_ENCODED_CHARGE_CURRENCY (2 << 5)
184 #define AST_AOC_ENCODED_CHARGE_UNIT     (3 << 5)
185
186 #define AST_AOC_ENCODED_CHARGE_SUBTOTAL (1 << 7)
187 #define AST_AOC_ENCODED_CHARGE_TOTAL    (0 << 7)
188
189 #define AST_AOC_ENCODE_VERSION 1
190
191
192 static char aoc_debug_enabled = 0;
193 static void aoc_display_decoded_debug(const struct ast_aoc_decoded *decoded, int decoding, struct ast_channel *chan);
194 static int aoc_s_add_entry(struct ast_aoc_decoded *decoded, struct ast_aoc_s_entry *entry);
195
196 /* AOC Payload Header. Holds all the encoded AOC data to pass on the wire */
197 struct ast_aoc_encoded {
198         uint8_t  version;
199         uint8_t  flags;
200         uint16_t datalen;
201         unsigned char data[0];
202 };
203
204 /* Decoded AOC data */
205 struct ast_aoc_decoded {
206         enum ast_aoc_type msg_type;
207         enum ast_aoc_charge_type charge_type;
208         enum ast_aoc_request request_flag;
209         enum ast_aoc_total_type total_type;
210
211         /* currency information */
212         enum ast_aoc_currency_multiplier multiplier;
213         unsigned int currency_amount;
214         char currency_name[AOC_CURRENCY_NAME_SIZE];
215
216         /* unit information */
217         int unit_count;
218         struct ast_aoc_unit_entry unit_list[32];
219
220         /* Billing Id */
221         enum ast_aoc_billing_id billing_id;
222
223         /* Charging Association information */
224         struct ast_aoc_charging_association charging_association;
225
226         /* AOC-S charge information */
227         int aoc_s_count;
228         struct ast_aoc_s_entry aoc_s_entries[10];
229
230         /* Is this an AOC Termination Request */
231         char termination_request;
232 };
233
234 /*! \brief AOC Payload Information Elements */
235 enum AOC_IE {
236         AOC_IE_CURRENCY = 1,
237         AOC_IE_UNIT = 2,
238         AOC_IE_BILLING = 3,
239         AOC_IE_CHARGING_ASSOCIATION = 4,
240         AOC_IE_RATE = 5,
241         AOC_IE_TERMINATION_REQUEST = 6,
242 };
243
244 /*! \brief AOC IE payload header */
245 struct aoc_pl_ie_hdr {
246         uint8_t ie_id;
247         uint8_t datalen;
248         char data[0];
249 } __attribute__((packed));
250
251 struct aoc_ie_currency {
252         uint32_t amount;
253         uint8_t  multiplier;
254         char name[AOC_CURRENCY_NAME_SIZE];
255 } __attribute__((packed));
256
257 struct aoc_ie_unit {
258         uint32_t amount;
259         uint8_t valid_type;
260         uint8_t valid_amount;
261         uint8_t type;
262 } __attribute__((packed));
263
264 struct aoc_ie_billing {
265         uint8_t id;
266 } __attribute__((packed));
267
268 struct aoc_ie_charging_association {
269         struct ast_aoc_charging_association ca;
270 } __attribute__((packed));
271
272 struct aoc_ie_charging_rate {
273         struct ast_aoc_s_entry entry;
274 } __attribute__((packed));
275
276 struct ast_aoc_decoded *ast_aoc_create(const enum ast_aoc_type msg_type,
277                 const enum ast_aoc_charge_type charge_type,
278                 const enum ast_aoc_request requests)
279 {
280         struct ast_aoc_decoded *decoded = NULL;
281
282         /* verify input */
283         if (((unsigned int) charge_type > AST_AOC_CHARGE_UNIT) ||
284                 ((unsigned int) msg_type > AST_AOC_E) ||
285                 ((msg_type == AST_AOC_REQUEST) && !requests)) {
286
287                 ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object, invalid input\n");
288                 return NULL;
289         }
290
291         if (!(decoded = ast_calloc(1, sizeof(struct ast_aoc_decoded)))) {
292                 ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object \n");
293                 return NULL;
294         }
295
296         decoded->msg_type = msg_type;
297
298         if (msg_type == AST_AOC_REQUEST) {
299                 decoded->request_flag = requests;
300         } else if ((msg_type == AST_AOC_D) || (msg_type == AST_AOC_E)) {
301                 decoded->charge_type = charge_type;
302         }
303
304         return decoded;
305 }
306
307 void *ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
308 {
309         ast_free(decoded);
310         return NULL;
311 }
312
313 void *ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
314 {
315         ast_free(encoded);
316         return NULL;
317 }
318
319 static void aoc_parse_ie_charging_rate(struct ast_aoc_decoded *decoded, const struct aoc_ie_charging_rate *ie)
320 {
321         struct ast_aoc_s_entry entry = { 0, };
322
323         entry.charged_item = ntohs(ie->entry.charged_item);
324         entry.rate_type = ntohs(ie->entry.rate_type);
325
326         switch (entry.rate_type) {
327         case AST_AOC_RATE_TYPE_DURATION:
328                 entry.rate.duration.multiplier = ntohs(ie->entry.rate.duration.multiplier);
329                 entry.rate.duration.amount = ntohl(ie->entry.rate.duration.amount);
330                 entry.rate.duration.time = ntohl(ie->entry.rate.duration.time);
331                 entry.rate.duration.time_scale = ntohs(ie->entry.rate.duration.time_scale);
332                 entry.rate.duration.granularity_time = ntohl(ie->entry.rate.duration.granularity_time);
333                 entry.rate.duration.granularity_time_scale = ntohs(ie->entry.rate.duration.granularity_time_scale);
334                 entry.rate.duration.charging_type = ie->entry.rate.duration.charging_type; /* only one byte */
335
336                 if (!ast_strlen_zero(ie->entry.rate.duration.currency_name)) {
337                         ast_copy_string(entry.rate.duration.currency_name,
338                                 ie->entry.rate.duration.currency_name,
339                                 sizeof(entry.rate.duration.currency_name));
340                 }
341                 break;
342         case AST_AOC_RATE_TYPE_FLAT:
343                 entry.rate.flat.multiplier = ntohs(ie->entry.rate.flat.multiplier);
344                 entry.rate.flat.amount = ntohl(ie->entry.rate.flat.amount);
345                 if (!ast_strlen_zero(ie->entry.rate.flat.currency_name)) {
346                         ast_copy_string(entry.rate.flat.currency_name,
347                                 ie->entry.rate.flat.currency_name,
348                                 sizeof(entry.rate.flat.currency_name));
349                 }
350                 break;
351         case AST_AOC_RATE_TYPE_VOLUME:
352                 entry.rate.volume.multiplier = ntohs(ie->entry.rate.volume.multiplier);
353                 entry.rate.volume.amount = ntohl(ie->entry.rate.volume.amount);
354                 entry.rate.volume.volume_unit = ntohs(ie->entry.rate.volume.volume_unit);
355                 if (!ast_strlen_zero(ie->entry.rate.volume.currency_name)) {
356                         ast_copy_string(entry.rate.volume.currency_name,
357                                 ie->entry.rate.volume.currency_name,
358                                 sizeof(entry.rate.volume.currency_name));
359                 }
360                 break;
361         case AST_AOC_RATE_TYPE_SPECIAL_CODE:
362                 entry.rate.special_code = ntohs(ie->entry.rate.special_code);
363                 break;
364         }
365
366         aoc_s_add_entry(decoded, &entry);
367 }
368
369 static int aoc_parse_ie(struct ast_aoc_decoded *decoded, unsigned char *data, unsigned int datalen)
370 {
371         enum AOC_IE ie_id;
372         unsigned int len;
373
374         while (datalen >= 2) {
375                 ie_id = data[0];
376                 len = data[1];
377                 if (len > datalen -2) {
378                         ast_log(LOG_ERROR, "AOC information element length exceeds the total message size\n");
379                         return -1;
380                 }
381
382                 switch(ie_id) {
383                 case AOC_IE_CURRENCY:
384                         if (len == sizeof(struct aoc_ie_currency)) {
385                                 struct aoc_ie_currency ie;
386                                 memcpy(&ie, data + 2, len);
387                                 decoded->currency_amount = ntohl(ie.amount);
388                                 decoded->multiplier = ie.multiplier; /* only one byte */
389                                 memcpy(decoded->currency_name, ie.name, sizeof(decoded->currency_name));
390                         } else {
391                                 ast_log(LOG_WARNING, "Received invalid currency ie\n");
392                         }
393                         break;
394                 case AOC_IE_UNIT:
395                         if (len == sizeof(struct aoc_ie_unit)) {
396                                 struct aoc_ie_unit ie;
397                                 memcpy(&ie, data + 2, len);
398                                 ast_aoc_add_unit_entry(decoded, ie.valid_amount, ntohl(ie.amount), ie.valid_type, ie.type);
399                         } else {
400                                 ast_log(LOG_WARNING, "Received invalid unit ie\n");
401                         }
402                         break;
403                 case AOC_IE_BILLING:
404                         if (len == sizeof(struct aoc_ie_billing)) {
405                                 struct aoc_ie_billing ie;
406                                 memcpy(&ie, data + 2, len);
407                                 decoded->billing_id = ie.id; /* only one byte */
408                         } else {
409                                 ast_log(LOG_WARNING, "Received invalid billing ie\n");
410                         }
411                         break;
412                 case AOC_IE_CHARGING_ASSOCIATION:
413                         if (len == sizeof(struct aoc_ie_charging_association)) {
414                                 memcpy(&decoded->charging_association, data + 2, sizeof(decoded->charging_association));
415                                 /* everything in the charging_association struct is a single byte except for the id */
416                                 if (decoded->charging_association.charging_type == AST_AOC_CHARGING_ASSOCIATION_ID) {
417                                         decoded->charging_association.charge.id = ntohl(decoded->charging_association.charge.id);
418                                 }
419                         } else {
420                                 ast_log(LOG_WARNING, "Received invalid charging association ie\n");
421                         }
422                         break;
423                 case AOC_IE_RATE:
424                         if (len == sizeof(struct aoc_ie_charging_rate)) {
425                                 struct aoc_ie_charging_rate ie;
426                                 memcpy(&ie, data + 2, len);
427                                 aoc_parse_ie_charging_rate(decoded, &ie);
428                         } else {
429                                 ast_log(LOG_WARNING, "Received invalid charging rate ie\n");
430                         }
431                         break;
432                 case AOC_IE_TERMINATION_REQUEST:
433                         if (len == 0) {
434                                 decoded->termination_request = 1;
435                         } else {
436                                 ast_log(LOG_WARNING, "Received invalid termination request ie\n");
437                         }
438                         break;
439                 default:
440                         ast_log(LOG_WARNING, "Unknown AOC Information Element, ignoring.\n");
441                 }
442
443                 datalen -= (len + 2);
444                 data += (len + 2);
445         }
446         return 0;
447 }
448
449 struct ast_aoc_decoded *ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan)
450 {
451         struct ast_aoc_decoded *decoded;
452
453         /* verify our encoded payload is actually large enough to hold all the ies */
454         if ((size - (sizeof(struct ast_aoc_encoded)) != ntohs(encoded->datalen))) {
455                 ast_log(LOG_WARNING, "Corrupted aoc encoded object, can not decode\n");
456                 return NULL;
457         }
458
459         if (!(decoded = ast_calloc(1, sizeof(struct ast_aoc_decoded)))) {
460                 ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object \n");
461                 return NULL;
462         }
463
464         /* decode flags */
465
466         if ((encoded->flags & AST_AOC_ENCODED_TYPE_S) == AST_AOC_ENCODED_TYPE_S) {
467                 decoded->msg_type = AST_AOC_S;
468         } else if (encoded->flags & AST_AOC_ENCODED_TYPE_E) {
469                 decoded->msg_type = AST_AOC_E;
470         } else if (encoded->flags & AST_AOC_ENCODED_TYPE_D) {
471                 decoded->msg_type = AST_AOC_D;
472         } else {
473                 decoded->msg_type = AST_AOC_REQUEST;
474         }
475
476         if (decoded->msg_type == AST_AOC_REQUEST) {
477                 if (encoded->flags & AST_AOC_ENCODED_REQUEST_S) {
478                         decoded->request_flag |= AST_AOC_REQUEST_S;
479                 }
480                 if (encoded->flags & AST_AOC_ENCODED_REQUEST_D) {
481                         decoded->request_flag |= AST_AOC_REQUEST_D;
482                 }
483                 if (encoded->flags & AST_AOC_ENCODED_REQUEST_E) {
484                         decoded->request_flag |= AST_AOC_REQUEST_E;
485                 }
486         } else if ((decoded->msg_type == AST_AOC_D) || (decoded->msg_type == AST_AOC_E)) {
487                 if ((encoded->flags & AST_AOC_ENCODED_CHARGE_UNIT) == AST_AOC_ENCODED_CHARGE_UNIT) {
488                         decoded->charge_type = AST_AOC_CHARGE_UNIT;
489                 } else if ((encoded->flags & AST_AOC_ENCODED_CHARGE_CURRENCY) == AST_AOC_ENCODED_CHARGE_CURRENCY) {
490                         decoded->charge_type = AST_AOC_CHARGE_CURRENCY;
491                 } else if ((encoded->flags & AST_AOC_ENCODED_CHARGE_FREE) == AST_AOC_ENCODED_CHARGE_FREE) {
492                         decoded->charge_type = AST_AOC_CHARGE_FREE;
493                 } else {
494                         decoded->charge_type = AST_AOC_CHARGE_NA;
495                 }
496
497                 if (encoded->flags & AST_AOC_ENCODED_CHARGE_SUBTOTAL) {
498                         decoded->total_type = AST_AOC_SUBTOTAL;
499                 }
500         }
501
502         /* decode information elements */
503         aoc_parse_ie(decoded, encoded->data, ntohs(encoded->datalen));
504
505         if (aoc_debug_enabled) {
506                 aoc_display_decoded_debug(decoded, 1, chan);
507         }
508
509         return decoded;
510 }
511
512 struct aoc_ie_data {
513         unsigned char buf[1024];
514         int pos;
515 };
516
517 /*!
518  * \internal
519  * \brief append an AOC information element
520  * \note data is expected to already be in network byte order at this point
521  */
522 static int aoc_append_ie(struct aoc_ie_data *ied, unsigned short ie_id, const void *data, unsigned short datalen)
523 {
524         if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
525                 ast_log(LOG_WARNING, "Failure to append AOC information element, out of space \n");
526                 return -1;
527         }
528         ied->buf[ied->pos++] = ie_id;
529         ied->buf[ied->pos++] = datalen;
530         if (datalen) {
531                 memcpy(ied->buf + ied->pos, data, datalen);
532                 ied->pos += datalen;
533         }
534         return 0;
535 }
536
537 static void aoc_create_ie_data_charging_rate(const struct ast_aoc_s_entry *entry, struct aoc_ie_charging_rate *ie)
538 {
539         ie->entry.charged_item = htons(entry->charged_item);
540         ie->entry.rate_type = htons(entry->rate_type);
541
542         switch (entry->rate_type) {
543         case AST_AOC_RATE_TYPE_DURATION:
544                 ie->entry.rate.duration.multiplier = htons(entry->rate.duration.multiplier);
545                 ie->entry.rate.duration.amount = htonl(entry->rate.duration.amount);
546                 ie->entry.rate.duration.time = htonl(entry->rate.duration.time);
547                 ie->entry.rate.duration.time_scale = htons(entry->rate.duration.time_scale);
548                 ie->entry.rate.duration.granularity_time = htonl(entry->rate.duration.granularity_time);
549                 ie->entry.rate.duration.granularity_time_scale = htons(entry->rate.duration.granularity_time_scale);
550                 ie->entry.rate.duration.charging_type = entry->rate.duration.charging_type; /* only one byte */
551
552                 if (!ast_strlen_zero(entry->rate.duration.currency_name)) {
553                         ast_copy_string(ie->entry.rate.duration.currency_name,
554                                 entry->rate.duration.currency_name,
555                                 sizeof(ie->entry.rate.duration.currency_name));
556                 }
557                 break;
558         case AST_AOC_RATE_TYPE_FLAT:
559                 ie->entry.rate.flat.multiplier = htons(entry->rate.flat.multiplier);
560                 ie->entry.rate.flat.amount = htonl(entry->rate.flat.amount);
561                 if (!ast_strlen_zero(entry->rate.flat.currency_name)) {
562                         ast_copy_string(ie->entry.rate.flat.currency_name,
563                                 entry->rate.flat.currency_name,
564                                 sizeof(ie->entry.rate.flat.currency_name));
565                 }
566                 break;
567         case AST_AOC_RATE_TYPE_VOLUME:
568                 ie->entry.rate.volume.multiplier = htons(entry->rate.volume.multiplier);
569                 ie->entry.rate.volume.amount = htonl(entry->rate.volume.amount);
570                 ie->entry.rate.volume.volume_unit = htons(entry->rate.volume.volume_unit);
571                 if (!ast_strlen_zero(entry->rate.volume.currency_name)) {
572                         ast_copy_string(ie->entry.rate.volume.currency_name,
573                                 entry->rate.volume.currency_name,
574                                 sizeof(ie->entry.rate.volume.currency_name));
575                 }
576                 break;
577         case AST_AOC_RATE_TYPE_SPECIAL_CODE:
578                 ie->entry.rate.special_code = htons(entry->rate.special_code);
579                 break;
580         }
581
582 }
583 static void aoc_create_ie_data(struct ast_aoc_decoded *decoded, struct aoc_ie_data *ied)
584 {
585         ied->pos = 0;
586
587         if (decoded->currency_amount) {
588                 struct aoc_ie_currency ie = {
589                         .amount = htonl(decoded->currency_amount),
590                         .multiplier = decoded->multiplier, /* only one byte */
591                         .name = { 0, },
592                 };
593
594                 if (!ast_strlen_zero(decoded->currency_name)) {
595                         ast_copy_string(ie.name, decoded->currency_name, sizeof(ie.name));
596                 }
597
598                 aoc_append_ie(ied, AOC_IE_CURRENCY, (const void *) &ie, sizeof(ie));
599         }
600
601         if (decoded->unit_count) {
602                 struct aoc_ie_unit ie = { 0 };
603                 int i;
604
605                 for (i = 0; i < decoded->unit_count; i++) {
606                         ie.valid_amount = decoded->unit_list[i].valid_amount; /* only one byte */
607                         ie.amount = htonl(decoded->unit_list[i].amount);
608                         ie.valid_type = decoded->unit_list[i].valid_type; /* only one byte */
609                         ie.type = decoded->unit_list[i].type; /* only one byte */
610                         aoc_append_ie(ied, AOC_IE_UNIT, (const void *) &ie, sizeof(ie));
611                 }
612         }
613
614         if (decoded->billing_id) {
615                 struct aoc_ie_billing ie;
616                 ie.id = decoded->billing_id; /* only one byte */
617                 aoc_append_ie(ied, AOC_IE_BILLING, (const void *) &ie, sizeof(ie));
618         }
619
620         if (decoded->charging_association.charging_type != AST_AOC_CHARGING_ASSOCIATION_NA) {
621                 struct aoc_ie_charging_association ie;
622                 memset(&ie, 0, sizeof(ie));
623                 ie.ca.charging_type = decoded->charging_association.charging_type;   /* only one byte */
624                 if (decoded->charging_association.charging_type == AST_AOC_CHARGING_ASSOCIATION_NUMBER) {
625                         ie.ca.charge.number.plan = decoded->charging_association.charge.number.plan; /* only one byte */
626                         ast_copy_string(ie.ca.charge.number.number,
627                                 decoded->charging_association.charge.number.number,
628                                 sizeof(ie.ca.charge.number.number));
629                 } else if (decoded->charging_association.charging_type == AST_AOC_CHARGING_ASSOCIATION_ID) {
630                         ie.ca.charge.id = htonl(decoded->charging_association.charge.id);
631                 }
632                 aoc_append_ie(ied, AOC_IE_CHARGING_ASSOCIATION, (const void *) &ie, sizeof(ie));
633         }
634
635         if (decoded->aoc_s_count) {
636                 struct aoc_ie_charging_rate ie;
637                 int i;
638                 for (i = 0; i < decoded->aoc_s_count; i++) {
639                         memset(&ie, 0, sizeof(ie));
640                         aoc_create_ie_data_charging_rate(&decoded->aoc_s_entries[i], &ie);
641                         aoc_append_ie(ied, AOC_IE_RATE, (const void *) &ie, sizeof(ie));
642                 }
643         }
644
645         if (decoded->termination_request) {
646                 aoc_append_ie(ied, AOC_IE_TERMINATION_REQUEST, NULL, 0);
647         }
648 }
649
650 struct ast_aoc_encoded *ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan)
651 {
652         struct aoc_ie_data ied;
653         struct ast_aoc_encoded *encoded = NULL;
654         size_t size = 0;
655
656         if (!decoded || !out_size) {
657                 return NULL;
658         }
659
660         *out_size = 0;
661
662         /* create information element buffer before allocating the payload,
663          * by doing this the exact size of the payload + the id data can be
664          * allocated all at once. */
665         aoc_create_ie_data(decoded, &ied);
666
667         size = sizeof(struct ast_aoc_encoded) + ied.pos;
668
669         if (!(encoded = ast_calloc(1, size))) {
670                 ast_log(LOG_WARNING, "Failed to create ast_aoc_encoded object during decode routine. \n");
671                 return NULL;
672         }
673
674         /* -- Set ie data buffer */
675         if (ied.pos) {
676                 /* this is safe because encoded was allocated to fit this perfectly */
677                 memcpy(encoded->data, ied.buf, ied.pos);
678                 encoded->datalen = htons(ied.pos);
679         }
680
681         /* --- Set Flags --- */
682         switch (decoded->msg_type) {
683         case AST_AOC_S:
684                 encoded->flags = AST_AOC_ENCODED_TYPE_S;
685                 break;
686         case AST_AOC_D:
687                 encoded->flags = AST_AOC_ENCODED_TYPE_D;
688                 break;
689         case AST_AOC_E:
690                 encoded->flags = AST_AOC_ENCODED_TYPE_E;
691                 break;
692         case AST_AOC_REQUEST:
693                 encoded->flags = AST_AOC_ENCODED_TYPE_REQUEST;
694         default:
695                 break;
696         }
697
698         /* if it is type request, set the types requested, else set charge type */
699         if (decoded->msg_type == AST_AOC_REQUEST) {
700                 if (decoded->request_flag & AST_AOC_REQUEST_S) {
701                         encoded->flags |= AST_AOC_ENCODED_REQUEST_S;
702                 }
703                 if (decoded->request_flag & AST_AOC_REQUEST_D) {
704                         encoded->flags |= AST_AOC_ENCODED_REQUEST_D;
705                 }
706                 if (decoded->request_flag & AST_AOC_REQUEST_E) {
707                         encoded->flags |= AST_AOC_ENCODED_REQUEST_E;
708                 }
709         } else if ((decoded->msg_type == AST_AOC_D) || (decoded->msg_type == AST_AOC_E)) {
710                 switch (decoded->charge_type) {
711                 case AST_AOC_CHARGE_UNIT:
712                         encoded->flags |= AST_AOC_ENCODED_CHARGE_UNIT;
713                         break;
714                 case AST_AOC_CHARGE_CURRENCY:
715                         encoded->flags |= AST_AOC_ENCODED_CHARGE_CURRENCY;
716                         break;
717                 case AST_AOC_CHARGE_FREE:
718                         encoded->flags |= AST_AOC_ENCODED_CHARGE_FREE;
719                 case AST_AOC_CHARGE_NA:
720                 default:
721                         encoded->flags |= AST_AOC_ENCODED_CHARGE_NA;
722                         break;
723                 }
724
725                 if (decoded->total_type == AST_AOC_SUBTOTAL) {
726                         encoded->flags |= AST_AOC_ENCODED_CHARGE_SUBTOTAL;
727                 }
728         }
729
730         /* --- Set Version Number --- */
731         encoded->version = AST_AOC_ENCODE_VERSION;
732
733         /* set the output size  */
734         *out_size = size;
735
736         if (aoc_debug_enabled) {
737                 aoc_display_decoded_debug(decoded, 0, chan);
738         }
739
740         return encoded;
741 }
742
743 static int aoc_s_add_entry(struct ast_aoc_decoded *decoded, struct ast_aoc_s_entry *entry)
744 {
745         if (decoded->aoc_s_count >= ARRAY_LEN(decoded->aoc_s_entries)) {
746                 return -1;
747         }
748
749         decoded->aoc_s_entries[decoded->aoc_s_count] = *entry;
750         decoded->aoc_s_count++;
751
752         return 0;
753 }
754
755
756 unsigned int ast_aoc_s_get_count(struct ast_aoc_decoded *decoded)
757 {
758         return decoded->aoc_s_count;
759 }
760
761 const struct ast_aoc_s_entry *ast_aoc_s_get_rate_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
762 {
763         if (entry_number >= decoded->aoc_s_count) {
764                 return NULL;
765         }
766
767         return (const struct ast_aoc_s_entry *) &decoded->aoc_s_entries[entry_number];
768 }
769
770 int ast_aoc_s_add_rate_duration(struct ast_aoc_decoded *decoded,
771         enum ast_aoc_s_charged_item charged_item,
772         unsigned int amount,
773         enum ast_aoc_currency_multiplier multiplier,
774         const char *currency_name,
775         unsigned long time,
776         enum ast_aoc_time_scale time_scale,
777         unsigned long granularity_time,
778         enum ast_aoc_time_scale granularity_time_scale,
779         int step_function)
780 {
781
782         struct ast_aoc_s_entry entry = { 0, };
783
784         entry.charged_item = charged_item;
785         entry.rate_type = AST_AOC_RATE_TYPE_DURATION;
786         entry.rate.duration.amount = amount;
787         entry.rate.duration.multiplier = multiplier;
788         entry.rate.duration.time = time;
789         entry.rate.duration.time_scale = time_scale;
790         entry.rate.duration.granularity_time = granularity_time;
791         entry.rate.duration.granularity_time_scale = granularity_time_scale;
792         entry.rate.duration.charging_type = step_function ? 1 : 0;
793
794         if (!ast_strlen_zero(currency_name)) {
795                 ast_copy_string(entry.rate.duration.currency_name, currency_name, sizeof(entry.rate.duration.currency_name));
796         }
797
798         return aoc_s_add_entry(decoded, &entry);
799 }
800
801 int ast_aoc_s_add_rate_flat(struct ast_aoc_decoded *decoded,
802         enum ast_aoc_s_charged_item charged_item,
803         unsigned int amount,
804         enum ast_aoc_currency_multiplier multiplier,
805         const char *currency_name)
806 {
807         struct ast_aoc_s_entry entry = { 0, };
808
809         entry.charged_item = charged_item;
810         entry.rate_type = AST_AOC_RATE_TYPE_FLAT;
811         entry.rate.flat.amount = amount;
812         entry.rate.flat.multiplier = multiplier;
813
814         if (!ast_strlen_zero(currency_name)) {
815                 ast_copy_string(entry.rate.flat.currency_name, currency_name, sizeof(entry.rate.flat.currency_name));
816         }
817
818         return aoc_s_add_entry(decoded, &entry);
819 }
820
821
822 int ast_aoc_s_add_rate_volume(struct ast_aoc_decoded *decoded,
823         enum ast_aoc_s_charged_item charged_item,
824         enum ast_aoc_volume_unit volume_unit,
825         unsigned int amount,
826         enum ast_aoc_currency_multiplier multiplier,
827         const char *currency_name)
828 {
829         struct ast_aoc_s_entry entry = { 0, };
830
831         entry.charged_item = charged_item;
832         entry.rate_type = AST_AOC_RATE_TYPE_VOLUME;
833         entry.rate.volume.multiplier = multiplier;
834         entry.rate.volume.amount = amount;
835         entry.rate.volume.volume_unit = volume_unit;
836
837         if (!ast_strlen_zero(currency_name)) {
838                 ast_copy_string(entry.rate.volume.currency_name, currency_name, sizeof(entry.rate.volume.currency_name));
839         }
840
841         return aoc_s_add_entry(decoded, &entry);
842 }
843
844 int ast_aoc_s_add_rate_special_charge_code(struct ast_aoc_decoded *decoded,
845         enum ast_aoc_s_charged_item charged_item,
846         unsigned int code)
847 {
848         struct ast_aoc_s_entry entry = { 0, };
849
850         entry.charged_item = charged_item;
851         entry.rate_type = AST_AOC_RATE_TYPE_SPECIAL_CODE;
852         entry.rate.special_code = code;
853
854         return aoc_s_add_entry(decoded, &entry);
855 }
856
857 int ast_aoc_s_add_rate_free(struct ast_aoc_decoded *decoded,
858         enum ast_aoc_s_charged_item charged_item,
859         int from_beginning)
860 {
861         struct ast_aoc_s_entry entry = { 0, };
862
863         entry.charged_item = charged_item;
864         entry.rate_type = from_beginning ? AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING : AST_AOC_RATE_TYPE_FREE;
865
866         return aoc_s_add_entry(decoded, &entry);
867 }
868
869 int ast_aoc_s_add_rate_na(struct ast_aoc_decoded *decoded,
870         enum ast_aoc_s_charged_item charged_item)
871 {
872         struct ast_aoc_s_entry entry = { 0, };
873
874         entry.charged_item = charged_item;
875         entry.rate_type = AST_AOC_RATE_TYPE_NA;
876
877         return aoc_s_add_entry(decoded, &entry);
878 }
879
880 int ast_aoc_s_add_special_arrangement(struct ast_aoc_decoded *decoded,
881         unsigned int code)
882 {
883         struct ast_aoc_s_entry entry = { 0, };
884
885         entry.charged_item = AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
886         entry.rate_type = AST_AOC_RATE_TYPE_SPECIAL_CODE;
887         entry.rate.special_code = code;
888
889         return aoc_s_add_entry(decoded, &entry);
890 }
891
892 enum ast_aoc_type ast_aoc_get_msg_type(struct ast_aoc_decoded *decoded)
893 {
894         return decoded->msg_type;
895 }
896
897 enum ast_aoc_charge_type ast_aoc_get_charge_type(struct ast_aoc_decoded *decoded)
898 {
899         return decoded->charge_type;
900 }
901
902 enum ast_aoc_request ast_aoc_get_request(struct ast_aoc_decoded *decoded)
903 {
904         return decoded->request_flag;
905 }
906
907 int ast_aoc_set_total_type(struct ast_aoc_decoded *decoded,
908         const enum ast_aoc_total_type type)
909 {
910         decoded->total_type = type;
911         return 0;
912 }
913
914 enum ast_aoc_total_type ast_aoc_get_total_type(struct ast_aoc_decoded *decoded)
915 {
916         return decoded->total_type;
917 }
918
919 int ast_aoc_set_currency_info(struct ast_aoc_decoded *decoded,
920                 const unsigned int amount,
921                 const enum ast_aoc_currency_multiplier multiplier,
922                 const char *name)
923 {
924
925         if (!ast_strlen_zero(name)) {
926                 ast_copy_string(decoded->currency_name, name, sizeof(decoded->currency_name));
927         }
928
929         decoded->currency_amount = amount;
930
931         if (multiplier && (multiplier < AST_AOC_MULT_NUM_ENTRIES)) {
932                 decoded->multiplier = multiplier;
933         } else {
934                 decoded->multiplier = AST_AOC_MULT_ONE;
935         }
936
937         return 0;
938 }
939
940 unsigned int ast_aoc_get_currency_amount(struct ast_aoc_decoded *decoded)
941 {
942         return decoded->currency_amount;
943 }
944
945 enum ast_aoc_currency_multiplier ast_aoc_get_currency_multiplier(struct ast_aoc_decoded *decoded)
946 {
947         return decoded->multiplier;
948 }
949
950 const char *ast_aoc_get_currency_multiplier_decimal(struct ast_aoc_decoded *decoded)
951 {
952         switch (decoded->multiplier) {
953         case AST_AOC_MULT_ONETHOUSANDTH:
954                 return "0.001";
955         case AST_AOC_MULT_ONEHUNDREDTH:
956                 return "0.01";
957         case AST_AOC_MULT_ONETENTH:
958                 return "0.1";
959         case AST_AOC_MULT_ONE:
960                 return "1.0";
961         case AST_AOC_MULT_TEN:
962                 return "10.0";
963         case AST_AOC_MULT_HUNDRED:
964                 return "100.0";
965         case AST_AOC_MULT_THOUSAND:
966                 return "1000.0";
967         default:
968                 return "1.0";
969         }
970 }
971
972 const char *ast_aoc_get_currency_name(struct ast_aoc_decoded *decoded)
973 {
974         return decoded->currency_name;
975 }
976
977 int ast_aoc_add_unit_entry(struct ast_aoc_decoded *decoded,
978                 const unsigned int amount_is_present,
979                 const unsigned int amount,
980                 const unsigned int type_is_present,
981                 const unsigned int type)
982 {
983         if ((decoded->msg_type == AST_AOC_REQUEST) ||
984                 (decoded->unit_count >= ARRAY_LEN(decoded->unit_list))) {
985                 return -1;
986         }
987
988         if (!amount_is_present && !type_is_present) {
989                 return -1;
990         }
991
992         decoded->unit_list[decoded->unit_count].valid_amount = amount_is_present;
993         if (amount_is_present) {
994                 decoded->unit_list[decoded->unit_count].amount = amount;
995         } else {
996                 decoded->unit_list[decoded->unit_count].amount = 0;
997         }
998
999         decoded->unit_list[decoded->unit_count].valid_type = type_is_present;
1000         if (type_is_present) {
1001                 decoded->unit_list[decoded->unit_count].type = type;
1002         } else {
1003                 decoded->unit_list[decoded->unit_count].type = 0;
1004         }
1005         decoded->unit_count++;
1006
1007         return 0;
1008 }
1009
1010 const struct ast_aoc_unit_entry *ast_aoc_get_unit_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
1011 {
1012         if (entry_number >= decoded->unit_count) {
1013                 return NULL;
1014         }
1015
1016         return (const struct ast_aoc_unit_entry *) &decoded->unit_list[entry_number];
1017 }
1018
1019 unsigned int ast_aoc_get_unit_count(struct ast_aoc_decoded *decoded)
1020 {
1021         return decoded->unit_count;
1022 }
1023
1024 int ast_aoc_set_billing_id(struct ast_aoc_decoded *decoded, const enum ast_aoc_billing_id id)
1025 {
1026         if ((id >= AST_AOC_BILLING_NUM_ENTRIES) || (id < AST_AOC_BILLING_NA)) {
1027                 return -1;
1028         }
1029
1030         decoded->billing_id = id;
1031
1032         return 0;
1033 }
1034
1035 enum ast_aoc_billing_id ast_aoc_get_billing_id(struct ast_aoc_decoded *decoded)
1036 {
1037         return decoded->billing_id;
1038 }
1039
1040 int ast_aoc_set_association_id(struct ast_aoc_decoded *decoded, const int id)
1041 {
1042         if (decoded->msg_type != AST_AOC_E) {
1043                 return -1;
1044         }
1045         memset(&decoded->charging_association, 0, sizeof(decoded->charging_association));
1046         decoded->charging_association.charging_type = AST_AOC_CHARGING_ASSOCIATION_ID;
1047         decoded->charging_association.charge.id = id;
1048         return 0;
1049 }
1050
1051 const struct ast_aoc_charging_association *ast_aoc_get_association_info(struct ast_aoc_decoded *decoded)
1052 {
1053         return &decoded->charging_association;
1054 }
1055
1056 int ast_aoc_set_association_number(struct ast_aoc_decoded *decoded, const char *num, uint8_t plan)
1057 {
1058         if ((decoded->msg_type != AST_AOC_E) || ast_strlen_zero(num)) {
1059                 return -1;
1060         }
1061         memset(&decoded->charging_association, 0, sizeof(decoded->charging_association));
1062         decoded->charging_association.charging_type = AST_AOC_CHARGING_ASSOCIATION_NUMBER;
1063         decoded->charging_association.charge.number.plan = plan;
1064         ast_copy_string(decoded->charging_association.charge.number.number, num, sizeof(decoded->charging_association.charge.number.number));
1065
1066         return 0;
1067 }
1068
1069 int ast_aoc_set_termination_request(struct ast_aoc_decoded *decoded)
1070 {
1071         if (decoded->msg_type != AST_AOC_REQUEST) {
1072                 return -1;
1073         }
1074         decoded->termination_request = 1;
1075
1076         return 0;
1077 }
1078
1079 int ast_aoc_get_termination_request(struct ast_aoc_decoded *decoded)
1080 {
1081         return decoded->termination_request;
1082 }
1083
1084 /*!
1085  * \internal
1086  * \brief Convert AST_AOC_VOLUME_UNIT to string.
1087  * \since 1.8
1088  *
1089  * \param value Value to convert to string.
1090  *
1091  * \return String equivalent.
1092  */
1093 static const char *aoc_volume_unit_str(enum ast_aoc_volume_unit value)
1094 {
1095         const char *str;
1096
1097         switch (value) {
1098         default:
1099         case AST_AOC_VOLUME_UNIT_OCTET:
1100                 str = "Octet";
1101                 break;
1102         case AST_AOC_VOLUME_UNIT_SEGMENT:
1103                 str = "Segment";
1104                 break;
1105         case AST_AOC_VOLUME_UNIT_MESSAGE:
1106                 str = "Message";
1107                 break;
1108         }
1109         return str;
1110 }
1111
1112 /*!
1113  * \internal
1114  * \brief Convert ast_aoc_charged_item to string.
1115  * \since 1.8
1116  *
1117  * \param value Value to convert to string.
1118  *
1119  * \return String equivalent.
1120  */
1121 static const char *aoc_charged_item_str(enum ast_aoc_s_charged_item value)
1122 {
1123         const char *str;
1124
1125         switch (value) {
1126         default:
1127         case AST_AOC_CHARGED_ITEM_NA:
1128                 str = "NotAvailable";
1129                 break;
1130         case AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT:
1131                 str = "SpecialArrangement";
1132                 break;
1133         case AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION:
1134                 str = "BasicCommunication";
1135                 break;
1136         case AST_AOC_CHARGED_ITEM_CALL_ATTEMPT:
1137                 str = "CallAttempt";
1138                 break;
1139         case AST_AOC_CHARGED_ITEM_CALL_SETUP:
1140                 str = "CallSetup";
1141                 break;
1142         case AST_AOC_CHARGED_ITEM_USER_USER_INFO:
1143                 str = "UserUserInfo";
1144                 break;
1145         case AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE:
1146                 str = "SupplementaryService";
1147                 break;
1148         }
1149         return str;
1150 }
1151
1152 /*!
1153  * \internal
1154  * \brief Convert ast_aoc_total_type to string.
1155  * \since 1.8
1156  *
1157  * \param value Value to convert to string.
1158  *
1159  * \return String equivalent.
1160  */
1161 static const char *aoc_type_of_totaling_str(enum ast_aoc_total_type value)
1162 {
1163         const char *str;
1164
1165         switch (value) {
1166         default:
1167         case AST_AOC_SUBTOTAL:
1168                 str = "SubTotal";
1169                 break;
1170         case AST_AOC_TOTAL:
1171                 str = "Total";
1172                 break;
1173         }
1174         return str;
1175 }
1176
1177 /*!
1178  * \internal
1179  * \brief Convert ast_aoc_rate_type to string.
1180  * \since 1.8
1181  *
1182  * \param value Value to convert to string.
1183  *
1184  * \return String equivalent.
1185  */
1186 static const char *aoc_rate_type_str(enum ast_aoc_s_rate_type value)
1187 {
1188         const char *str;
1189
1190         switch (value) {
1191         default:
1192         case AST_AOC_RATE_TYPE_NA:
1193                 str = "NotAvailable";
1194                 break;
1195         case AST_AOC_RATE_TYPE_FREE:
1196                 str = "Free";
1197                 break;
1198         case AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING:
1199                 str = "FreeFromBeginning";
1200                 break;
1201         case AST_AOC_RATE_TYPE_DURATION:
1202                 str = "Duration";
1203                 break;
1204         case AST_AOC_RATE_TYPE_FLAT:
1205                 str = "Flat";
1206                 break;
1207         case AST_AOC_RATE_TYPE_VOLUME:
1208                 str = "Volume";
1209                 break;
1210         case AST_AOC_RATE_TYPE_SPECIAL_CODE:
1211                 str = "SpecialCode";
1212                 break;
1213         }
1214         return str;
1215 }
1216
1217 /*!
1218  * \internal
1219  * \brief Convert AST_AOC_TIME_SCALE to string.
1220  * \since 1.8
1221  *
1222  * \param value Value to convert to string.
1223  *
1224  * \return String equivalent.
1225  */
1226 static const char *aoc_scale_str(enum ast_aoc_time_scale value)
1227 {
1228         const char *str;
1229
1230         switch (value) {
1231         default:
1232         case AST_AOC_TIME_SCALE_HUNDREDTH_SECOND:
1233                 str = "OneHundredthSecond";
1234                 break;
1235         case AST_AOC_TIME_SCALE_TENTH_SECOND:
1236                 str = "OneTenthSecond";
1237                 break;
1238         case AST_AOC_TIME_SCALE_SECOND:
1239                 str = "Second";
1240                 break;
1241         case AST_AOC_TIME_SCALE_TEN_SECOND:
1242                 str = "TenSeconds";
1243                 break;
1244         case AST_AOC_TIME_SCALE_MINUTE:
1245                 str = "Minute";
1246                 break;
1247         case AST_AOC_TIME_SCALE_HOUR:
1248                 str = "Hour";
1249                 break;
1250         case AST_AOC_TIME_SCALE_DAY:
1251                 str = "Day";
1252                 break;
1253         }
1254         return str;
1255 }
1256
1257 static const char *aoc_charge_type_str(enum ast_aoc_charge_type value)
1258 {
1259         const char *str;
1260
1261         switch (value) {
1262         default:
1263         case AST_AOC_CHARGE_NA:
1264                 str = "NotAvailable";
1265                 break;
1266         case AST_AOC_CHARGE_FREE:
1267                 str = "Free";
1268                 break;
1269         case AST_AOC_CHARGE_CURRENCY:
1270                 str = "Currency";
1271                 break;
1272         case AST_AOC_CHARGE_UNIT:
1273                 str = "Units";
1274                 break;
1275         }
1276
1277         return str;
1278 }
1279
1280 static const char *aoc_multiplier_str(enum ast_aoc_currency_multiplier mult)
1281 {
1282         switch (mult) {
1283         case AST_AOC_MULT_ONETHOUSANDTH:
1284                 return "1/1000";
1285         case AST_AOC_MULT_ONEHUNDREDTH:
1286                 return "1/100";
1287         case AST_AOC_MULT_ONETENTH:
1288                 return "1/10";
1289         case AST_AOC_MULT_ONE:
1290                 return "1";
1291         case AST_AOC_MULT_TEN:
1292                 return "10";
1293         case AST_AOC_MULT_HUNDRED:
1294                 return "100";
1295         case AST_AOC_MULT_THOUSAND:
1296                 return "1000";
1297         case AST_AOC_MULT_NUM_ENTRIES:
1298                 break;
1299         }
1300         return "1";
1301 }
1302
1303 static const char *aoc_billingid_str(enum ast_aoc_billing_id billing_id)
1304 {
1305         switch (billing_id) {
1306         case AST_AOC_BILLING_NORMAL:
1307                 return "Normal";
1308         case AST_AOC_BILLING_REVERSE_CHARGE:
1309                 return "Reverse";
1310         case AST_AOC_BILLING_CREDIT_CARD:
1311                 return "CreditCard";
1312         case AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL:
1313                 return "CallForwardingUnconditional";
1314         case AST_AOC_BILLING_CALL_FWD_BUSY:
1315                 return "CallForwardingBusy";
1316         case AST_AOC_BILLING_CALL_FWD_NO_REPLY:
1317                 return "CallForwardingNoReply";
1318         case AST_AOC_BILLING_CALL_DEFLECTION:
1319                 return "CallDeflection";
1320         case AST_AOC_BILLING_CALL_TRANSFER:
1321                 return "CallTransfer";
1322         case AST_AOC_BILLING_NA:
1323                 return "NotAvailable";
1324         case AST_AOC_BILLING_NUM_ENTRIES:
1325                 break;
1326         }
1327         return "NotAvailable";
1328 }
1329
1330 int ast_aoc_test_encode_decode_match(struct ast_aoc_decoded *decoded)
1331 {
1332         struct ast_aoc_decoded *new_decoded = NULL;
1333         struct ast_aoc_encoded *encoded = NULL;
1334         size_t size;
1335         int res = 0;
1336
1337         if (!(encoded = ast_aoc_encode(decoded, &size, NULL))) {
1338                 return -1;
1339         }
1340
1341         if (!(new_decoded = ast_aoc_decode(encoded, size, NULL))) {
1342                 ast_free(encoded);
1343                 return -1;
1344         }
1345
1346         if (memcmp(new_decoded, decoded, sizeof(struct ast_aoc_decoded))) {
1347                 res = -1;
1348         }
1349
1350         ast_aoc_destroy_decoded(new_decoded);
1351         ast_aoc_destroy_encoded(encoded);
1352         return res;
1353 }
1354
1355 static char *aoc_cli_debug_enable(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1356 {
1357         switch (cmd) {
1358         case CLI_INIT:
1359                 e->command = "aoc set debug";
1360                 e->usage =
1361                         "Usage: 'aoc set debug on' to enable aoc debug, 'aoc set debug off' to disable debug.\n";
1362                 return NULL;
1363         case CLI_GENERATE:
1364                 return NULL;
1365         case CLI_HANDLER:
1366                 if (a->argc != 4) {
1367                         return CLI_SHOWUSAGE;
1368                 } else if(ast_true(a->argv[3])) {
1369                         ast_cli(a->fd, "aoc debug enabled\n");
1370                         aoc_debug_enabled = 1;
1371                 } else if (ast_false(a->argv[3])) {
1372                         ast_cli(a->fd, "aoc debug disabled\n");
1373                         aoc_debug_enabled = 0;
1374                 } else {
1375                         return CLI_SHOWUSAGE;
1376                 }
1377         }
1378
1379         return CLI_SUCCESS;
1380 }
1381
1382 /*!
1383  * \internal
1384  * \brief Append the time structure to the event message string.
1385  * \since 1.8
1386  *
1387  * \param msg Event message string being built.
1388  * \param prefix Prefix to add to the amount lines.
1389  * \param name Name of the time structure to convert.
1390  * \param time Data to convert.
1391  * \param scale Data to convert.
1392  *
1393  * \return Nothing
1394  */
1395 static void aoc_time_str(struct ast_str **msg, const char *prefix, const char *name, unsigned long time, enum ast_aoc_time_scale scale)
1396 {
1397         ast_str_append(msg, 0, "%s/%s/Length: %lu\r\n", prefix, name, time);
1398         ast_str_append(msg, 0, "%s/%s/Scale: %s\r\n", prefix, name,
1399                 aoc_scale_str(scale));
1400 }
1401
1402 /*!
1403  * \internal
1404  * \brief Append the amount structure to the event message string.
1405  * \since 1.8
1406  *
1407  * \param msg Event message string being built.
1408  * \param prefix Prefix to add to the amount lines.
1409  * \param amount Data to convert.
1410  * \param multipler to convert
1411  *
1412  * \return Nothing
1413  */
1414 static void aoc_amount_str(struct ast_str **msg, const char *prefix, unsigned int amount, enum ast_aoc_currency_multiplier mult)
1415 {
1416         static const char name[] = "Amount";
1417
1418         ast_str_append(msg, 0, "%s/%s/Cost: %u\r\n", prefix, name, amount);
1419         ast_str_append(msg, 0, "%s/%s/Multiplier: %s\r\n", prefix, name,
1420                 aoc_multiplier_str(mult));
1421 }
1422
1423 static void aoc_request_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
1424 {
1425         if (decoded->request_flag) {
1426                 ast_str_append(msg, 0, "AOCRequest:");
1427                 if (decoded->request_flag & AST_AOC_REQUEST_S) {
1428                         ast_str_append(msg, 0, "S");
1429                 }
1430                 if (decoded->request_flag & AST_AOC_REQUEST_D) {
1431                         ast_str_append(msg, 0, "D");
1432                 }
1433                 if (decoded->request_flag & AST_AOC_REQUEST_E) {
1434                         ast_str_append(msg, 0, "E");
1435                 }
1436                 ast_str_append(msg, 0, "\r\n");
1437
1438         } else {
1439                 ast_str_append(msg, 0, "AOCRequest: NONE\r\n");
1440         }
1441 }
1442
1443 static void aoc_s_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
1444 {
1445         const char *rate_str;
1446         char prefix[32];
1447         int idx;
1448
1449         ast_str_append(msg, 0, "NumberRates: %d\r\n", decoded->aoc_s_count);
1450         for (idx = 0; idx < decoded->aoc_s_count; ++idx) {
1451                 snprintf(prefix, sizeof(prefix), "Rate(%d)", idx);
1452
1453                 ast_str_append(msg, 0, "%s/Chargeable: %s\r\n", prefix,
1454                         aoc_charged_item_str(decoded->aoc_s_entries[idx].charged_item));
1455                 if (decoded->aoc_s_entries[idx].charged_item == AST_AOC_CHARGED_ITEM_NA) {
1456                         continue;
1457                 }
1458                 rate_str = aoc_rate_type_str(decoded->aoc_s_entries[idx].rate_type);
1459                 ast_str_append(msg, 0, "%s/Type: %s\r\n", prefix, rate_str);
1460                 switch (decoded->aoc_s_entries[idx].rate_type) {
1461                 case AST_AOC_RATE_TYPE_DURATION:
1462                         strcat(prefix, "/");
1463                         strcat(prefix, rate_str);
1464                         ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
1465                                 decoded->aoc_s_entries[idx].rate.duration.currency_name);
1466                         aoc_amount_str(msg, prefix,
1467                                 decoded->aoc_s_entries[idx].rate.duration.amount,
1468                                 decoded->aoc_s_entries[idx].rate.duration.multiplier);
1469                         ast_str_append(msg, 0, "%s/ChargingType: %s\r\n", prefix,
1470                                 decoded->aoc_s_entries[idx].rate.duration.charging_type ?
1471                                 "StepFunction" : "ContinuousCharging");
1472                         aoc_time_str(msg, prefix, "Time",
1473                                 decoded->aoc_s_entries[idx].rate.duration.time,
1474                                 decoded->aoc_s_entries[idx].rate.duration.time_scale);
1475                         if (decoded->aoc_s_entries[idx].rate.duration.granularity_time) {
1476                                 aoc_time_str(msg, prefix, "Granularity",
1477                                         decoded->aoc_s_entries[idx].rate.duration.granularity_time,
1478                                         decoded->aoc_s_entries[idx].rate.duration.granularity_time_scale);
1479                         }
1480                         break;
1481                 case AST_AOC_RATE_TYPE_FLAT:
1482                         strcat(prefix, "/");
1483                         strcat(prefix, rate_str);
1484                         ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
1485                                 decoded->aoc_s_entries[idx].rate.flat.currency_name);
1486                         aoc_amount_str(msg, prefix,
1487                                 decoded->aoc_s_entries[idx].rate.flat.amount,
1488                                 decoded->aoc_s_entries[idx].rate.flat.multiplier);
1489                         break;
1490                 case AST_AOC_RATE_TYPE_VOLUME:
1491                         strcat(prefix, "/");
1492                         strcat(prefix, rate_str);
1493                         ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
1494                                 decoded->aoc_s_entries[idx].rate.volume.currency_name);
1495                         aoc_amount_str(msg, prefix,
1496                                 decoded->aoc_s_entries[idx].rate.volume.amount,
1497                                 decoded->aoc_s_entries[idx].rate.volume.multiplier);
1498                         ast_str_append(msg, 0, "%s/Unit: %s\r\n", prefix,
1499                                 aoc_volume_unit_str(decoded->aoc_s_entries[idx].rate.volume.volume_unit));
1500                         break;
1501                 case AST_AOC_RATE_TYPE_SPECIAL_CODE:
1502                         ast_str_append(msg, 0, "%s/%s: %d\r\n", prefix, rate_str,
1503                                 decoded->aoc_s_entries[idx].rate.special_code);
1504                         break;
1505                 default:
1506                         break;
1507                 }
1508         }
1509 }
1510
1511 static void aoc_d_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
1512 {
1513         const char *charge_str;
1514         int idx;
1515         char prefix[32];
1516
1517         charge_str = aoc_charge_type_str(decoded->charge_type);
1518         ast_str_append(msg, 0, "Type: %s\r\n", charge_str);
1519
1520         switch (decoded->charge_type) {
1521         case AST_AOC_CHARGE_CURRENCY:
1522         case AST_AOC_CHARGE_UNIT:
1523                 ast_str_append(msg, 0, "BillingID: %s\r\n",
1524                         aoc_billingid_str(decoded->billing_id));
1525                 ast_str_append(msg, 0, "TypeOfCharging: %s\r\n",
1526                         aoc_type_of_totaling_str(decoded->total_type));
1527                 break;
1528         default:
1529                 break;
1530         }
1531
1532         switch (decoded->charge_type) {
1533         case AST_AOC_CHARGE_CURRENCY:
1534                 ast_str_append(msg, 0, "%s: %s\r\n", charge_str,
1535                         decoded->currency_name);
1536                 aoc_amount_str(msg, charge_str,
1537                         decoded->currency_amount,
1538                         decoded->multiplier);
1539                 break;
1540         case AST_AOC_CHARGE_UNIT:
1541                 ast_str_append(msg, 0, "%s/NumberItems: %d\r\n", charge_str,
1542                         decoded->unit_count);
1543                 for (idx = 0; idx < decoded->unit_count; ++idx) {
1544                         snprintf(prefix, sizeof(prefix), "%s/Item(%d)", charge_str, idx);
1545                         if (decoded->unit_list[idx].valid_amount) {
1546                                 ast_str_append(msg, 0, "%s/NumberOf: %u\r\n", prefix,
1547                                         decoded->unit_list[idx].amount);
1548                         }
1549                         if (decoded->unit_list[idx].valid_type) {
1550                                 ast_str_append(msg, 0, "%s/TypeOf: %u\r\n", prefix,
1551                                         decoded->unit_list[idx].type);
1552                         }
1553                 }
1554                 break;
1555         default:
1556                 break;
1557         }
1558 }
1559
1560 static void aoc_e_event(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
1561 {
1562         const char *charge_str;
1563         int idx;
1564         char prefix[32];
1565
1566         charge_str = "ChargingAssociation";
1567
1568         switch (decoded->charging_association.charging_type) {
1569         case AST_AOC_CHARGING_ASSOCIATION_NUMBER:
1570                 snprintf(prefix, sizeof(prefix), "%s/Number", charge_str);
1571                 ast_str_append(msg, 0, "%s: %s\r\n", prefix,
1572                         decoded->charging_association.charge.number.number);
1573                 ast_str_append(msg, 0, "%s/Plan: %d\r\n", prefix,
1574                         decoded->charging_association.charge.number.plan);
1575                 break;
1576         case AST_AOC_CHARGING_ASSOCIATION_ID:
1577                 ast_str_append(msg, 0, "%s/ID: %d\r\n", charge_str, decoded->charging_association.charge.id);
1578                 break;
1579         case AST_AOC_CHARGING_ASSOCIATION_NA:
1580         default:
1581                 break;
1582         }
1583
1584         charge_str = aoc_charge_type_str(decoded->charge_type);
1585         ast_str_append(msg, 0, "Type: %s\r\n", charge_str);
1586         switch (decoded->charge_type) {
1587         case AST_AOC_CHARGE_CURRENCY:
1588         case AST_AOC_CHARGE_UNIT:
1589                 ast_str_append(msg, 0, "BillingID: %s\r\n",
1590                         aoc_billingid_str(decoded->billing_id));
1591                 break;
1592         default:
1593                 break;
1594         }
1595         switch (decoded->charge_type) {
1596         case AST_AOC_CHARGE_CURRENCY:
1597                 ast_str_append(msg, 0, "%s: %s\r\n", charge_str,
1598                         decoded->currency_name);
1599                 aoc_amount_str(msg, charge_str,
1600                         decoded->currency_amount,
1601                         decoded->multiplier);
1602                 break;
1603         case AST_AOC_CHARGE_UNIT:
1604                 ast_str_append(msg, 0, "%s/NumberItems: %d\r\n", charge_str,
1605                         decoded->unit_count);
1606                 for (idx = 0; idx < decoded->unit_count; ++idx) {
1607                         snprintf(prefix, sizeof(prefix), "%s/Item(%d)", charge_str, idx);
1608                         if (decoded->unit_list[idx].valid_amount) {
1609                                 ast_str_append(msg, 0, "%s/NumberOf: %u\r\n", prefix,
1610                                         decoded->unit_list[idx].amount);
1611                         }
1612                         if (decoded->unit_list[idx].valid_type) {
1613                                 ast_str_append(msg, 0, "%s/TypeOf: %u\r\n", prefix,
1614                                         decoded->unit_list[idx].type);
1615                         }
1616                 }
1617                 break;
1618         default:
1619                 break;
1620         }
1621 }
1622
1623 static struct ast_json *units_to_json(const struct ast_aoc_decoded *decoded)
1624 {
1625         int i;
1626         struct ast_json *units = ast_json_array_create();
1627
1628         if (!units) {
1629                 return ast_json_null();
1630         }
1631
1632         for (i = 0; i < decoded->unit_count; ++i) {
1633                 struct ast_json *unit = ast_json_object_create();
1634
1635                 if (decoded->unit_list[i].valid_amount) {
1636                         ast_json_object_set(
1637                                 unit, "NumberOf", ast_json_stringf(
1638                                         "%u", decoded->unit_list[i].amount));
1639                         }
1640
1641                 if (decoded->unit_list[i].valid_type) {
1642                         ast_json_object_set(
1643                                 unit, "TypeOf", ast_json_stringf(
1644                                         "%u", decoded->unit_list[i].type));
1645                 }
1646
1647                 if (ast_json_array_append(units, unit)) {
1648                         break;
1649                 }
1650         }
1651
1652         return units;
1653 }
1654
1655 static struct ast_json *currency_to_json(const char *name, int cost,
1656                                          enum ast_aoc_currency_multiplier mult)
1657 {
1658         return ast_json_pack("{s:s, s:i, s:s}",
1659                 "Name", AST_JSON_UTF8_VALIDATE(name),
1660                 "Cost", cost,
1661                 "Multiplier", aoc_multiplier_str(mult));
1662 }
1663
1664 static struct ast_json *charge_to_json(const struct ast_aoc_decoded *decoded)
1665 {
1666         struct ast_json *obj;
1667         const char *obj_type;
1668
1669         if (decoded->charge_type != AST_AOC_CHARGE_CURRENCY &&
1670             decoded->charge_type != AST_AOC_CHARGE_UNIT) {
1671                 return ast_json_pack("{s:s}",
1672                         "Type", aoc_charge_type_str(decoded->charge_type));
1673         }
1674
1675         if (decoded->charge_type == AST_AOC_CHARGE_CURRENCY) {
1676                 obj_type = "Currency";
1677                 obj = currency_to_json(decoded->currency_name, decoded->currency_amount,
1678                                        decoded->multiplier);
1679         } else { /* decoded->charge_type == AST_AOC_CHARGE_UNIT */
1680                 obj_type = "Units";
1681                 obj = units_to_json(decoded);
1682         }
1683
1684         return ast_json_pack("{s:s, s:s, s:s, s:o}",
1685                 "Type", aoc_charge_type_str(decoded->charge_type),
1686                 "BillingID", aoc_billingid_str(decoded->billing_id),
1687                 "TotalType", aoc_type_of_totaling_str(decoded->total_type),
1688                 obj_type, obj);
1689 }
1690
1691 static struct ast_json *association_to_json(const struct ast_aoc_decoded *decoded)
1692 {
1693         switch (decoded->charging_association.charging_type) {
1694         case AST_AOC_CHARGING_ASSOCIATION_NUMBER:
1695                 return ast_json_pack("{s:s, s:i}",
1696                         "Number", AST_JSON_UTF8_VALIDATE(decoded->charging_association.charge.number.number),
1697                         "Plan", decoded->charging_association.charge.number.plan);
1698         case AST_AOC_CHARGING_ASSOCIATION_ID:
1699                 return ast_json_pack("{s:i}", "ID", decoded->charging_association.charge.id);
1700         case AST_AOC_CHARGING_ASSOCIATION_NA:
1701         default:
1702                 return ast_json_null();
1703         }
1704 }
1705
1706 static struct ast_json *s_to_json(const struct ast_aoc_decoded *decoded)
1707 {
1708         int i;
1709         struct ast_json *rates = ast_json_array_create();
1710
1711         if (!rates) {
1712                 return ast_json_null();
1713         }
1714
1715         for (i = 0; i < decoded->aoc_s_count; ++i) {
1716                 struct ast_json *rate;
1717                 struct ast_json *type = NULL;
1718                 struct ast_json *currency;
1719                 const char *charge_item = aoc_charged_item_str(
1720                         decoded->aoc_s_entries[i].charged_item);
1721
1722                 if (decoded->aoc_s_entries[i].charged_item == AST_AOC_CHARGED_ITEM_NA) {
1723                         rate = ast_json_pack("{s:s}", "Chargeable", charge_item);
1724                         if (ast_json_array_append(rates, rate)) {
1725                                 break;
1726                         }
1727                         continue;
1728                 }
1729
1730                 switch (decoded->aoc_s_entries[i].rate_type) {
1731                 case AST_AOC_RATE_TYPE_DURATION:
1732                 {
1733                         struct ast_json *time;
1734                         struct ast_json *granularity = NULL;
1735
1736                         currency = currency_to_json(
1737                                 decoded->aoc_s_entries[i].rate.duration.currency_name,
1738                                 decoded->aoc_s_entries[i].rate.duration.amount,
1739                                 decoded->aoc_s_entries[i].rate.duration.multiplier);
1740
1741                         time = ast_json_pack("{s:i, s:i}",
1742                                 "Length", decoded->aoc_s_entries[i].rate.duration.time,
1743                                 "Scale", decoded->aoc_s_entries[i].rate.duration.time_scale);
1744
1745                         if (decoded->aoc_s_entries[i].rate.duration.granularity_time) {
1746                                 granularity = ast_json_pack("{s:i, s:i}",
1747                                         "Length", decoded->aoc_s_entries[i].rate.duration.granularity_time,
1748                                         "Scale", decoded->aoc_s_entries[i].rate.duration.granularity_time_scale);
1749                         }
1750
1751                         type = ast_json_pack("{s:o, s:s, s:o, s:o}",
1752                                 "Currency", currency,
1753                                 "ChargingType", decoded->aoc_s_entries[i].rate.duration.charging_type
1754                                         ? "StepFunction" : "ContinuousCharging",
1755                                 "Time", time,
1756                                 "Granularity", granularity ?: ast_json_null());
1757
1758                         break;
1759                 }
1760                 case AST_AOC_RATE_TYPE_FLAT:
1761                         currency = currency_to_json(
1762                                 decoded->aoc_s_entries[i].rate.flat.currency_name,
1763                                 decoded->aoc_s_entries[i].rate.flat.amount,
1764                                 decoded->aoc_s_entries[i].rate.flat.multiplier);
1765
1766                         type = ast_json_pack("{s:o}", "Currency", currency);
1767                         break;
1768                 case AST_AOC_RATE_TYPE_VOLUME:
1769                         currency = currency_to_json(
1770                                 decoded->aoc_s_entries[i].rate.volume.currency_name,
1771                                 decoded->aoc_s_entries[i].rate.volume.amount,
1772                                 decoded->aoc_s_entries[i].rate.volume.multiplier);
1773
1774                         type = ast_json_pack("{s:s, s:o}",
1775                                 "Unit", aoc_volume_unit_str(
1776                                         decoded->aoc_s_entries[i].rate.volume.volume_unit),
1777                                 "Currency", currency);
1778                         break;
1779                 case AST_AOC_RATE_TYPE_SPECIAL_CODE:
1780                         type = ast_json_pack("{s:i}",
1781                                 "SpecialCode", decoded->aoc_s_entries[i].rate.special_code);
1782                         break;
1783                 default:
1784                         break;
1785                 }
1786
1787                 rate = ast_json_pack("{s:s, s:o}",
1788                         "Chargeable", charge_item,
1789                         aoc_rate_type_str(decoded->aoc_s_entries[i].rate_type), type);
1790                 if (ast_json_array_append(rates, rate)) {
1791                         break;
1792                 }
1793         }
1794         return rates;
1795 }
1796
1797 static struct ast_json *d_to_json(const struct ast_aoc_decoded *decoded)
1798 {
1799         return ast_json_pack("{s:o}", "Charge", charge_to_json(decoded));
1800 }
1801
1802 static struct ast_json *e_to_json(const struct ast_aoc_decoded *decoded)
1803 {
1804         return ast_json_pack("{s:o, s:o}",
1805                              "ChargingAssociation", association_to_json(decoded),
1806                              "Charge", charge_to_json(decoded));
1807 }
1808
1809 struct aoc_event_blob {
1810         /*! Channel AOC event is associated with (NULL for unassociated) */
1811         struct ast_channel_snapshot *snapshot;
1812         /*! AOC JSON blob of data */
1813         struct ast_json *blob;
1814 };
1815
1816 static void aoc_event_blob_dtor(void *obj)
1817 {
1818         struct aoc_event_blob *aoc_event = obj;
1819
1820         ao2_cleanup(aoc_event->snapshot);
1821         ast_json_unref(aoc_event->blob);
1822 }
1823
1824 /*!
1825  * \internal
1826  * \brief Publish an AOC event.
1827  * \since 13.3.0
1828  *
1829  * \param chan Channel associated with the AOC event. (May be NULL if no channel)
1830  * \param msg_type What kind of AOC event.
1831  * \param blob AOC data blob to publish.
1832  *
1833  * \return Nothing
1834  */
1835 static void aoc_publish_blob(struct ast_channel *chan, struct stasis_message_type *msg_type, struct ast_json *blob)
1836 {
1837         struct stasis_message *msg;
1838         struct aoc_event_blob *aoc_event;
1839
1840         if (!blob || ast_json_is_null(blob)) {
1841                 /* No AOC blob information?  Nothing to send an event about. */
1842                 return;
1843         }
1844
1845         aoc_event = ao2_alloc_options(sizeof(*aoc_event), aoc_event_blob_dtor,
1846                 AO2_ALLOC_OPT_LOCK_NOLOCK);
1847         if (!aoc_event) {
1848                 return;
1849         }
1850
1851         if (chan) {
1852                 aoc_event->snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
1853                 if (!aoc_event->snapshot) {
1854                         ao2_ref(aoc_event, -1);
1855                         return;
1856                 }
1857         }
1858         aoc_event->blob = ast_json_ref(blob);
1859
1860         msg = stasis_message_create(msg_type, aoc_event);
1861         ao2_ref(aoc_event, -1);
1862
1863         if (msg) {
1864                 stasis_publish(ast_manager_get_topic(), msg);
1865                 ao2_ref(msg, -1);
1866         }
1867 }
1868
1869 static struct ast_manager_event_blob *aoc_to_ami(struct stasis_message *message,
1870                                                  const char *event_name)
1871 {
1872         struct aoc_event_blob *aoc_event = stasis_message_data(message);
1873         struct ast_str *channel = NULL;
1874         struct ast_str *aoc;
1875         struct ast_manager_event_blob *ev = NULL;
1876
1877         if (aoc_event->snapshot) {
1878                 channel = ast_manager_build_channel_state_string(aoc_event->snapshot);
1879                 if (!channel) {
1880                         return NULL;
1881                 }
1882         }
1883
1884         aoc = ast_manager_str_from_json_object(aoc_event->blob, NULL);
1885         if (aoc && !ast_strlen_zero(ast_str_buffer(aoc))) {
1886                 ev = ast_manager_event_blob_create(EVENT_FLAG_AOC, event_name, "%s%s",
1887                         AS_OR(channel, ""), ast_str_buffer(aoc));
1888         }
1889
1890         ast_free(aoc);
1891         ast_free(channel);
1892         return ev;
1893 }
1894
1895 static struct ast_manager_event_blob *aoc_s_to_ami(struct stasis_message *message)
1896 {
1897         return aoc_to_ami(message, "AOC-S");
1898 }
1899
1900 static struct ast_manager_event_blob *aoc_d_to_ami(struct stasis_message *message)
1901 {
1902         return aoc_to_ami(message, "AOC-D");
1903 }
1904
1905 static struct ast_manager_event_blob *aoc_e_to_ami(struct stasis_message *message)
1906 {
1907         return aoc_to_ami(message, "AOC-E");
1908 }
1909
1910 struct stasis_message_type *aoc_s_type(void);
1911 struct stasis_message_type *aoc_d_type(void);
1912 struct stasis_message_type *aoc_e_type(void);
1913
1914 STASIS_MESSAGE_TYPE_DEFN(
1915         aoc_s_type,
1916         .to_ami = aoc_s_to_ami);
1917
1918 STASIS_MESSAGE_TYPE_DEFN(
1919         aoc_d_type,
1920         .to_ami = aoc_d_to_ami);
1921
1922 STASIS_MESSAGE_TYPE_DEFN(
1923         aoc_e_type,
1924         .to_ami = aoc_e_to_ami);
1925
1926 int ast_aoc_manager_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan)
1927 {
1928         struct ast_json *blob;
1929         struct stasis_message_type *msg_type;
1930
1931         if (!decoded) {
1932                 return -1;
1933         }
1934
1935         switch (decoded->msg_type) {
1936         case AST_AOC_S:
1937                 blob = s_to_json(decoded);
1938                 msg_type = aoc_s_type();
1939                 break;
1940         case AST_AOC_D:
1941                 blob = d_to_json(decoded);
1942                 msg_type = aoc_d_type();
1943                 break;
1944         case AST_AOC_E:
1945                 blob = e_to_json(decoded);
1946                 msg_type = aoc_e_type();
1947                 break;
1948         default:
1949                 /* events for AST_AOC_REQUEST are not generated here */
1950                 return 0;
1951         }
1952
1953         aoc_publish_blob(chan, msg_type, blob);
1954         ast_json_unref(blob);
1955         return 0;
1956 }
1957
1958 int ast_aoc_decoded2str(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
1959 {
1960         if (!decoded || !msg) {
1961                 return -1;
1962         }
1963
1964         switch (decoded->msg_type) {
1965         case AST_AOC_S:
1966                 ast_str_append(msg, 0, "AOC-S\r\n");
1967                 aoc_s_event(decoded, msg);
1968                 break;
1969         case AST_AOC_D:
1970                 ast_str_append(msg, 0, "AOC-D\r\n");
1971                 aoc_d_event(decoded, msg);
1972                 break;
1973         case AST_AOC_E:
1974                 ast_str_append(msg, 0, "AOC-E\r\n");
1975                 aoc_e_event(decoded, msg);
1976                 break;
1977         case AST_AOC_REQUEST:
1978                 ast_str_append(msg, 0, "AOC-Request\r\n");
1979                 aoc_request_event(decoded, msg);
1980                 break;
1981         }
1982
1983         return 0;
1984 }
1985
1986 static void aoc_display_decoded_debug(const struct ast_aoc_decoded *decoded, int decoding, struct ast_channel *chan)
1987 {
1988         struct ast_str *msg;
1989
1990         if (!decoded || !(msg = ast_str_create(1024))) {
1991                 return;
1992         }
1993
1994         if (decoding) {
1995                 ast_str_append(&msg, 0, "---- DECODED AOC MSG ----\r\n");
1996         } else {
1997                 ast_str_append(&msg, 0, "---- ENCODED AOC MSG ----\r\n");
1998         }
1999         if (chan) {
2000                 ast_str_append(&msg, 0, "CHANNEL: %s\r\n", ast_channel_name(chan));
2001         }
2002
2003         if (ast_aoc_decoded2str(decoded, &msg)) {
2004                 ast_free(msg);
2005                 return;
2006         }
2007
2008         ast_verb(1, "%s\r\n", ast_str_buffer(msg));
2009         ast_free(msg);
2010 }
2011
2012 static struct ast_cli_entry aoc_cli[] = {
2013         AST_CLI_DEFINE(aoc_cli_debug_enable, "enable cli debugging of AOC messages"),
2014 };
2015
2016 static void aoc_shutdown(void)
2017 {
2018         STASIS_MESSAGE_TYPE_CLEANUP(aoc_s_type);
2019         STASIS_MESSAGE_TYPE_CLEANUP(aoc_d_type);
2020         STASIS_MESSAGE_TYPE_CLEANUP(aoc_e_type);
2021
2022         ast_cli_unregister_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
2023 }
2024 int ast_aoc_cli_init(void)
2025 {
2026         STASIS_MESSAGE_TYPE_INIT(aoc_s_type);
2027         STASIS_MESSAGE_TYPE_INIT(aoc_d_type);
2028         STASIS_MESSAGE_TYPE_INIT(aoc_e_type);
2029
2030         ast_register_cleanup(aoc_shutdown);
2031         return ast_cli_register_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
2032 }