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