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