aoc.c 55 KB

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