aoc.c 55 KB

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