aoc.c 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617
  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. /* Encoded Payload Flags */
  36. #define AST_AOC_ENCODED_TYPE_REQUEST (0 << 0)
  37. #define AST_AOC_ENCODED_TYPE_D (1 << 0)
  38. #define AST_AOC_ENCODED_TYPE_E (2 << 0)
  39. #define AST_AOC_ENCODED_TYPE_S (3 << 0)
  40. #define AST_AOC_ENCODED_REQUEST_S (1 << 2)
  41. #define AST_AOC_ENCODED_REQUEST_D (1 << 3)
  42. #define AST_AOC_ENCODED_REQUEST_E (1 << 4)
  43. #define AST_AOC_ENCODED_CHARGE_NA (0 << 5)
  44. #define AST_AOC_ENCODED_CHARGE_FREE (1 << 5)
  45. #define AST_AOC_ENCODED_CHARGE_CURRENCY (2 << 5)
  46. #define AST_AOC_ENCODED_CHARGE_UNIT (3 << 5)
  47. #define AST_AOC_ENCODED_CHARGE_SUBTOTAL (1 << 7)
  48. #define AST_AOC_ENCODED_CHARGE_TOTAL (0 << 7)
  49. #define AST_AOC_ENCODE_VERSION 1
  50. static char aoc_debug_enabled = 0;
  51. static void aoc_display_decoded_debug(const struct ast_aoc_decoded *decoded, int decoding, struct ast_channel *chan);
  52. static int aoc_s_add_entry(struct ast_aoc_decoded *decoded, struct ast_aoc_s_entry *entry);
  53. /* AOC Payload Header. Holds all the encoded AOC data to pass on the wire */
  54. struct ast_aoc_encoded {
  55. uint8_t version;
  56. uint8_t flags;
  57. uint16_t datalen;
  58. unsigned char data[0];
  59. };
  60. /* Decoded AOC data */
  61. struct ast_aoc_decoded {
  62. enum ast_aoc_type msg_type;
  63. enum ast_aoc_charge_type charge_type;
  64. enum ast_aoc_request request_flag;
  65. enum ast_aoc_total_type total_type;
  66. /* currency information */
  67. enum ast_aoc_currency_multiplier multiplier;
  68. unsigned int currency_amount;
  69. char currency_name[AOC_CURRENCY_NAME_SIZE];
  70. /* unit information */
  71. int unit_count;
  72. struct ast_aoc_unit_entry unit_list[32];
  73. /* Billing Id */
  74. enum ast_aoc_billing_id billing_id;
  75. /* Charging Association information */
  76. struct ast_aoc_charging_association charging_association;
  77. /* AOC-S charge information */
  78. int aoc_s_count;
  79. struct ast_aoc_s_entry aoc_s_entries[10];
  80. /* Is this an AOC Termination Request */
  81. char termination_request;
  82. };
  83. /*! \brief AOC Payload Information Elements */
  84. enum AOC_IE {
  85. AOC_IE_CURRENCY = 1,
  86. AOC_IE_UNIT = 2,
  87. AOC_IE_BILLING = 3,
  88. AOC_IE_CHARGING_ASSOCIATION = 4,
  89. AOC_IE_RATE = 5,
  90. AOC_IE_TERMINATION_REQUEST = 6,
  91. };
  92. /*! \brief AOC IE payload header */
  93. struct aoc_pl_ie_hdr {
  94. uint8_t ie_id;
  95. uint8_t datalen;
  96. char data[0];
  97. } __attribute__((packed));
  98. struct aoc_ie_currency {
  99. uint32_t amount;
  100. uint8_t multiplier;
  101. char name[AOC_CURRENCY_NAME_SIZE];
  102. } __attribute__((packed));
  103. struct aoc_ie_unit {
  104. uint32_t amount;
  105. uint8_t valid_type;
  106. uint8_t valid_amount;
  107. uint8_t type;
  108. } __attribute__((packed));
  109. struct aoc_ie_billing {
  110. uint8_t id;
  111. } __attribute__((packed));
  112. struct aoc_ie_charging_association {
  113. struct ast_aoc_charging_association ca;
  114. } __attribute__((packed));
  115. struct aoc_ie_charging_rate {
  116. struct ast_aoc_s_entry entry;
  117. } __attribute__((packed));
  118. struct ast_aoc_decoded *ast_aoc_create(const enum ast_aoc_type msg_type,
  119. const enum ast_aoc_charge_type charge_type,
  120. const enum ast_aoc_request requests)
  121. {
  122. struct ast_aoc_decoded *decoded = NULL;
  123. /* verify input */
  124. if (((unsigned int) charge_type > AST_AOC_CHARGE_UNIT) ||
  125. ((unsigned int) msg_type > AST_AOC_E) ||
  126. ((msg_type == AST_AOC_REQUEST) && !requests)) {
  127. ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object, invalid input\n");
  128. return NULL;
  129. }
  130. if (!(decoded = ast_calloc(1, sizeof(struct ast_aoc_decoded)))) {
  131. ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object \n");
  132. return NULL;
  133. }
  134. decoded->msg_type = msg_type;
  135. if (msg_type == AST_AOC_REQUEST) {
  136. decoded->request_flag = requests;
  137. } else if ((msg_type == AST_AOC_D) || (msg_type == AST_AOC_E)) {
  138. decoded->charge_type = charge_type;
  139. }
  140. return decoded;
  141. }
  142. void *ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
  143. {
  144. ast_free(decoded);
  145. return NULL;
  146. }
  147. void *ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
  148. {
  149. ast_free(encoded);
  150. return NULL;
  151. }
  152. static void aoc_parse_ie_charging_rate(struct ast_aoc_decoded *decoded, const struct aoc_ie_charging_rate *ie)
  153. {
  154. struct ast_aoc_s_entry entry = { 0, };
  155. entry.charged_item = ntohs(ie->entry.charged_item);
  156. entry.rate_type = ntohs(ie->entry.rate_type);
  157. switch (entry.rate_type) {
  158. case AST_AOC_RATE_TYPE_DURATION:
  159. entry.rate.duration.multiplier = ntohs(ie->entry.rate.duration.multiplier);
  160. entry.rate.duration.amount = ntohl(ie->entry.rate.duration.amount);
  161. entry.rate.duration.time = ntohl(ie->entry.rate.duration.time);
  162. entry.rate.duration.time_scale = ntohs(ie->entry.rate.duration.time_scale);
  163. entry.rate.duration.granularity_time = ntohl(ie->entry.rate.duration.granularity_time);
  164. entry.rate.duration.granularity_time_scale = ntohs(ie->entry.rate.duration.granularity_time_scale);
  165. entry.rate.duration.charging_type = ie->entry.rate.duration.charging_type; /* only one byte */
  166. if (!ast_strlen_zero(ie->entry.rate.duration.currency_name)) {
  167. ast_copy_string(entry.rate.duration.currency_name,
  168. ie->entry.rate.duration.currency_name,
  169. sizeof(entry.rate.duration.currency_name));
  170. }
  171. break;
  172. case AST_AOC_RATE_TYPE_FLAT:
  173. entry.rate.flat.multiplier = ntohs(ie->entry.rate.flat.multiplier);
  174. entry.rate.flat.amount = ntohl(ie->entry.rate.flat.amount);
  175. if (!ast_strlen_zero(ie->entry.rate.flat.currency_name)) {
  176. ast_copy_string(entry.rate.flat.currency_name,
  177. ie->entry.rate.flat.currency_name,
  178. sizeof(entry.rate.flat.currency_name));
  179. }
  180. break;
  181. case AST_AOC_RATE_TYPE_VOLUME:
  182. entry.rate.volume.multiplier = ntohs(ie->entry.rate.volume.multiplier);
  183. entry.rate.volume.amount = ntohl(ie->entry.rate.volume.amount);
  184. entry.rate.volume.volume_unit = ntohs(ie->entry.rate.volume.volume_unit);
  185. if (!ast_strlen_zero(ie->entry.rate.volume.currency_name)) {
  186. ast_copy_string(entry.rate.volume.currency_name,
  187. ie->entry.rate.volume.currency_name,
  188. sizeof(entry.rate.volume.currency_name));
  189. }
  190. break;
  191. case AST_AOC_RATE_TYPE_SPECIAL_CODE:
  192. entry.rate.special_code = ntohs(ie->entry.rate.special_code);
  193. break;
  194. }
  195. aoc_s_add_entry(decoded, &entry);
  196. }
  197. static int aoc_parse_ie(struct ast_aoc_decoded *decoded, unsigned char *data, unsigned int datalen)
  198. {
  199. enum AOC_IE ie_id;
  200. unsigned int len;
  201. while (datalen >= 2) {
  202. ie_id = data[0];
  203. len = data[1];
  204. if (len > datalen -2) {
  205. ast_log(LOG_ERROR, "AOC information element length exceeds the total message size\n");
  206. return -1;
  207. }
  208. switch(ie_id) {
  209. case AOC_IE_CURRENCY:
  210. if (len == sizeof(struct aoc_ie_currency)) {
  211. struct aoc_ie_currency ie;
  212. memcpy(&ie, data + 2, len);
  213. decoded->currency_amount = ntohl(ie.amount);
  214. decoded->multiplier = ie.multiplier; /* only one byte */
  215. memcpy(decoded->currency_name, ie.name, sizeof(decoded->currency_name));
  216. } else {
  217. ast_log(LOG_WARNING, "Received invalid currency ie\n");
  218. }
  219. break;
  220. case AOC_IE_UNIT:
  221. if (len == sizeof(struct aoc_ie_unit)) {
  222. struct aoc_ie_unit ie;
  223. memcpy(&ie, data + 2, len);
  224. ast_aoc_add_unit_entry(decoded, ie.valid_amount, ntohl(ie.amount), ie.valid_type, ie.type);
  225. } else {
  226. ast_log(LOG_WARNING, "Received invalid unit ie\n");
  227. }
  228. break;
  229. case AOC_IE_BILLING:
  230. if (len == sizeof(struct aoc_ie_billing)) {
  231. struct aoc_ie_billing ie;
  232. memcpy(&ie, data + 2, len);
  233. decoded->billing_id = ie.id; /* only one byte */
  234. } else {
  235. ast_log(LOG_WARNING, "Received invalid billing ie\n");
  236. }
  237. break;
  238. case AOC_IE_CHARGING_ASSOCIATION:
  239. if (len == sizeof(struct aoc_ie_charging_association)) {
  240. memcpy(&decoded->charging_association, data + 2, sizeof(decoded->charging_association));
  241. /* everything in the charging_association struct is a single byte except for the id */
  242. if (decoded->charging_association.charging_type == AST_AOC_CHARGING_ASSOCIATION_ID) {
  243. decoded->charging_association.charge.id = ntohl(decoded->charging_association.charge.id);
  244. }
  245. } else {
  246. ast_log(LOG_WARNING, "Received invalid charging association ie\n");
  247. }
  248. break;
  249. case AOC_IE_RATE:
  250. if (len == sizeof(struct aoc_ie_charging_rate)) {
  251. struct aoc_ie_charging_rate ie;
  252. memcpy(&ie, data + 2, len);
  253. aoc_parse_ie_charging_rate(decoded, &ie);
  254. } else {
  255. ast_log(LOG_WARNING, "Received invalid charging rate ie\n");
  256. }
  257. break;
  258. case AOC_IE_TERMINATION_REQUEST:
  259. if (len == 0) {
  260. decoded->termination_request = 1;
  261. } else {
  262. ast_log(LOG_WARNING, "Received invalid termination request ie\n");
  263. }
  264. break;
  265. default:
  266. ast_log(LOG_WARNING, "Unknown AOC Information Element, ignoring.\n");
  267. }
  268. datalen -= (len + 2);
  269. data += (len + 2);
  270. }
  271. return 0;
  272. }
  273. struct ast_aoc_decoded *ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan)
  274. {
  275. struct ast_aoc_decoded *decoded;
  276. /* verify our encoded payload is actually large enough to hold all the ies */
  277. if ((size - (sizeof(struct ast_aoc_encoded)) != ntohs(encoded->datalen))) {
  278. ast_log(LOG_WARNING, "Corrupted aoc encoded object, can not decode\n");
  279. return NULL;
  280. }
  281. if (!(decoded = ast_calloc(1, sizeof(struct ast_aoc_decoded)))) {
  282. ast_log(LOG_WARNING, "Failed to create ast_aoc_decoded object \n");
  283. return NULL;
  284. }
  285. /* decode flags */
  286. if ((encoded->flags & AST_AOC_ENCODED_TYPE_S) == AST_AOC_ENCODED_TYPE_S) {
  287. decoded->msg_type = AST_AOC_S;
  288. } else if (encoded->flags & AST_AOC_ENCODED_TYPE_E) {
  289. decoded->msg_type = AST_AOC_E;
  290. } else if (encoded->flags & AST_AOC_ENCODED_TYPE_D) {
  291. decoded->msg_type = AST_AOC_D;
  292. } else {
  293. decoded->msg_type = AST_AOC_REQUEST;
  294. }
  295. if (decoded->msg_type == AST_AOC_REQUEST) {
  296. if (encoded->flags & AST_AOC_ENCODED_REQUEST_S) {
  297. decoded->request_flag |= AST_AOC_REQUEST_S;
  298. }
  299. if (encoded->flags & AST_AOC_ENCODED_REQUEST_D) {
  300. decoded->request_flag |= AST_AOC_REQUEST_D;
  301. }
  302. if (encoded->flags & AST_AOC_ENCODED_REQUEST_E) {
  303. decoded->request_flag |= AST_AOC_REQUEST_E;
  304. }
  305. } else if ((decoded->msg_type == AST_AOC_D) || (decoded->msg_type == AST_AOC_E)) {
  306. if ((encoded->flags & AST_AOC_ENCODED_CHARGE_UNIT) == AST_AOC_ENCODED_CHARGE_UNIT) {
  307. decoded->charge_type = AST_AOC_CHARGE_UNIT;
  308. } else if ((encoded->flags & AST_AOC_ENCODED_CHARGE_CURRENCY) == AST_AOC_ENCODED_CHARGE_CURRENCY) {
  309. decoded->charge_type = AST_AOC_CHARGE_CURRENCY;
  310. } else if ((encoded->flags & AST_AOC_ENCODED_CHARGE_FREE) == AST_AOC_ENCODED_CHARGE_FREE) {
  311. decoded->charge_type = AST_AOC_CHARGE_FREE;
  312. } else {
  313. decoded->charge_type = AST_AOC_CHARGE_NA;
  314. }
  315. if (encoded->flags & AST_AOC_ENCODED_CHARGE_SUBTOTAL) {
  316. decoded->total_type = AST_AOC_SUBTOTAL;
  317. }
  318. }
  319. /* decode information elements */
  320. aoc_parse_ie(decoded, encoded->data, ntohs(encoded->datalen));
  321. if (aoc_debug_enabled) {
  322. aoc_display_decoded_debug(decoded, 1, chan);
  323. }
  324. return decoded;
  325. }
  326. struct aoc_ie_data {
  327. unsigned char buf[1024];
  328. int pos;
  329. };
  330. /*!
  331. * \internal
  332. * \brief append an AOC information element
  333. * \note data is expected to already be in network byte order at this point
  334. */
  335. static int aoc_append_ie(struct aoc_ie_data *ied, unsigned short ie_id, const void *data, unsigned short datalen)
  336. {
  337. if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
  338. ast_log(LOG_WARNING, "Failure to append AOC information element, out of space \n");
  339. return -1;
  340. }
  341. ied->buf[ied->pos++] = ie_id;
  342. ied->buf[ied->pos++] = datalen;
  343. if (datalen) {
  344. memcpy(ied->buf + ied->pos, data, datalen);
  345. ied->pos += datalen;
  346. }
  347. return 0;
  348. }
  349. static void aoc_create_ie_data_charging_rate(const struct ast_aoc_s_entry *entry, struct aoc_ie_charging_rate *ie)
  350. {
  351. ie->entry.charged_item = htons(entry->charged_item);
  352. ie->entry.rate_type = htons(entry->rate_type);
  353. switch (entry->rate_type) {
  354. case AST_AOC_RATE_TYPE_DURATION:
  355. ie->entry.rate.duration.multiplier = htons(entry->rate.duration.multiplier);
  356. ie->entry.rate.duration.amount = htonl(entry->rate.duration.amount);
  357. ie->entry.rate.duration.time = htonl(entry->rate.duration.time);
  358. ie->entry.rate.duration.time_scale = htons(entry->rate.duration.time_scale);
  359. ie->entry.rate.duration.granularity_time = htonl(entry->rate.duration.granularity_time);
  360. ie->entry.rate.duration.granularity_time_scale = htons(entry->rate.duration.granularity_time_scale);
  361. ie->entry.rate.duration.charging_type = entry->rate.duration.charging_type; /* only one byte */
  362. if (!ast_strlen_zero(entry->rate.duration.currency_name)) {
  363. ast_copy_string(ie->entry.rate.duration.currency_name,
  364. entry->rate.duration.currency_name,
  365. sizeof(ie->entry.rate.duration.currency_name));
  366. }
  367. break;
  368. case AST_AOC_RATE_TYPE_FLAT:
  369. ie->entry.rate.flat.multiplier = htons(entry->rate.flat.multiplier);
  370. ie->entry.rate.flat.amount = htonl(entry->rate.flat.amount);
  371. if (!ast_strlen_zero(entry->rate.flat.currency_name)) {
  372. ast_copy_string(ie->entry.rate.flat.currency_name,
  373. entry->rate.flat.currency_name,
  374. sizeof(ie->entry.rate.flat.currency_name));
  375. }
  376. break;
  377. case AST_AOC_RATE_TYPE_VOLUME:
  378. ie->entry.rate.volume.multiplier = htons(entry->rate.volume.multiplier);
  379. ie->entry.rate.volume.amount = htonl(entry->rate.volume.amount);
  380. ie->entry.rate.volume.volume_unit = htons(entry->rate.volume.volume_unit);
  381. if (!ast_strlen_zero(entry->rate.volume.currency_name)) {
  382. ast_copy_string(ie->entry.rate.volume.currency_name,
  383. entry->rate.volume.currency_name,
  384. sizeof(ie->entry.rate.volume.currency_name));
  385. }
  386. break;
  387. case AST_AOC_RATE_TYPE_SPECIAL_CODE:
  388. ie->entry.rate.special_code = htons(entry->rate.special_code);
  389. break;
  390. }
  391. }
  392. static void aoc_create_ie_data(struct ast_aoc_decoded *decoded, struct aoc_ie_data *ied)
  393. {
  394. ied->pos = 0;
  395. if (decoded->currency_amount) {
  396. struct aoc_ie_currency ie = {
  397. .amount = htonl(decoded->currency_amount),
  398. .multiplier = decoded->multiplier, /* only one byte */
  399. .name = { 0, },
  400. };
  401. if (!ast_strlen_zero(decoded->currency_name)) {
  402. ast_copy_string(ie.name, decoded->currency_name, sizeof(ie.name));
  403. }
  404. aoc_append_ie(ied, AOC_IE_CURRENCY, (const void *) &ie, sizeof(ie));
  405. }
  406. if (decoded->unit_count) {
  407. struct aoc_ie_unit ie = { 0 };
  408. int i;
  409. for (i = 0; i < decoded->unit_count; i++) {
  410. ie.valid_amount = decoded->unit_list[i].valid_amount; /* only one byte */
  411. ie.amount = htonl(decoded->unit_list[i].amount);
  412. ie.valid_type = decoded->unit_list[i].valid_type; /* only one byte */
  413. ie.type = decoded->unit_list[i].type; /* only one byte */
  414. aoc_append_ie(ied, AOC_IE_UNIT, (const void *) &ie, sizeof(ie));
  415. }
  416. }
  417. if (decoded->billing_id) {
  418. struct aoc_ie_billing ie;
  419. ie.id = decoded->billing_id; /* only one byte */
  420. aoc_append_ie(ied, AOC_IE_BILLING, (const void *) &ie, sizeof(ie));
  421. }
  422. if (decoded->charging_association.charging_type != AST_AOC_CHARGING_ASSOCIATION_NA) {
  423. struct aoc_ie_charging_association ie;
  424. memset(&ie, 0, sizeof(ie));
  425. ie.ca.charging_type = decoded->charging_association.charging_type; /* only one byte */
  426. if (decoded->charging_association.charging_type == AST_AOC_CHARGING_ASSOCIATION_NUMBER) {
  427. ie.ca.charge.number.plan = decoded->charging_association.charge.number.plan; /* only one byte */
  428. ast_copy_string(ie.ca.charge.number.number,
  429. decoded->charging_association.charge.number.number,
  430. sizeof(ie.ca.charge.number.number));
  431. } else if (decoded->charging_association.charging_type == AST_AOC_CHARGING_ASSOCIATION_ID) {
  432. ie.ca.charge.id = htonl(decoded->charging_association.charge.id);
  433. }
  434. aoc_append_ie(ied, AOC_IE_CHARGING_ASSOCIATION, (const void *) &ie, sizeof(ie));
  435. }
  436. if (decoded->aoc_s_count) {
  437. struct aoc_ie_charging_rate ie;
  438. int i;
  439. for (i = 0; i < decoded->aoc_s_count; i++) {
  440. memset(&ie, 0, sizeof(ie));
  441. aoc_create_ie_data_charging_rate(&decoded->aoc_s_entries[i], &ie);
  442. aoc_append_ie(ied, AOC_IE_RATE, (const void *) &ie, sizeof(ie));
  443. }
  444. }
  445. if (decoded->termination_request) {
  446. aoc_append_ie(ied, AOC_IE_TERMINATION_REQUEST, NULL, 0);
  447. }
  448. }
  449. struct ast_aoc_encoded *ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan)
  450. {
  451. struct aoc_ie_data ied;
  452. struct ast_aoc_encoded *encoded = NULL;
  453. size_t size = 0;
  454. if (!decoded || !out_size) {
  455. return NULL;
  456. }
  457. *out_size = 0;
  458. /* create information element buffer before allocating the payload,
  459. * by doing this the exact size of the payload + the id data can be
  460. * allocated all at once. */
  461. aoc_create_ie_data(decoded, &ied);
  462. size = sizeof(struct ast_aoc_encoded) + ied.pos;
  463. if (!(encoded = ast_calloc(1, size))) {
  464. ast_log(LOG_WARNING, "Failed to create ast_aoc_encoded object during decode routine. \n");
  465. return NULL;
  466. }
  467. /* -- Set ie data buffer */
  468. if (ied.pos) {
  469. /* this is safe because encoded was allocated to fit this perfectly */
  470. memcpy(encoded->data, ied.buf, ied.pos);
  471. encoded->datalen = htons(ied.pos);
  472. }
  473. /* --- Set Flags --- */
  474. switch (decoded->msg_type) {
  475. case AST_AOC_S:
  476. encoded->flags = AST_AOC_ENCODED_TYPE_S;
  477. break;
  478. case AST_AOC_D:
  479. encoded->flags = AST_AOC_ENCODED_TYPE_D;
  480. break;
  481. case AST_AOC_E:
  482. encoded->flags = AST_AOC_ENCODED_TYPE_E;
  483. break;
  484. case AST_AOC_REQUEST:
  485. encoded->flags = AST_AOC_ENCODED_TYPE_REQUEST;
  486. default:
  487. break;
  488. }
  489. /* if it is type request, set the types requested, else set charge type */
  490. if (decoded->msg_type == AST_AOC_REQUEST) {
  491. if (decoded->request_flag & AST_AOC_REQUEST_S) {
  492. encoded->flags |= AST_AOC_ENCODED_REQUEST_S;
  493. }
  494. if (decoded->request_flag & AST_AOC_REQUEST_D) {
  495. encoded->flags |= AST_AOC_ENCODED_REQUEST_D;
  496. }
  497. if (decoded->request_flag & AST_AOC_REQUEST_E) {
  498. encoded->flags |= AST_AOC_ENCODED_REQUEST_E;
  499. }
  500. } else if ((decoded->msg_type == AST_AOC_D) || (decoded->msg_type == AST_AOC_E)) {
  501. switch (decoded->charge_type) {
  502. case AST_AOC_CHARGE_UNIT:
  503. encoded->flags |= AST_AOC_ENCODED_CHARGE_UNIT;
  504. break;
  505. case AST_AOC_CHARGE_CURRENCY:
  506. encoded->flags |= AST_AOC_ENCODED_CHARGE_CURRENCY;
  507. break;
  508. case AST_AOC_CHARGE_FREE:
  509. encoded->flags |= AST_AOC_ENCODED_CHARGE_FREE;
  510. case AST_AOC_CHARGE_NA:
  511. default:
  512. encoded->flags |= AST_AOC_ENCODED_CHARGE_NA;
  513. break;
  514. }
  515. if (decoded->total_type == AST_AOC_SUBTOTAL) {
  516. encoded->flags |= AST_AOC_ENCODED_CHARGE_SUBTOTAL;
  517. }
  518. }
  519. /* --- Set Version Number --- */
  520. encoded->version = AST_AOC_ENCODE_VERSION;
  521. /* set the output size */
  522. *out_size = size;
  523. if (aoc_debug_enabled) {
  524. aoc_display_decoded_debug(decoded, 0, chan);
  525. }
  526. return encoded;
  527. }
  528. static int aoc_s_add_entry(struct ast_aoc_decoded *decoded, struct ast_aoc_s_entry *entry)
  529. {
  530. if (decoded->aoc_s_count >= ARRAY_LEN(decoded->aoc_s_entries)) {
  531. return -1;
  532. }
  533. decoded->aoc_s_entries[decoded->aoc_s_count] = *entry;
  534. decoded->aoc_s_count++;
  535. return 0;
  536. }
  537. unsigned int ast_aoc_s_get_count(struct ast_aoc_decoded *decoded)
  538. {
  539. return decoded->aoc_s_count;
  540. }
  541. const struct ast_aoc_s_entry *ast_aoc_s_get_rate_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
  542. {
  543. if (entry_number >= decoded->aoc_s_count) {
  544. return NULL;
  545. }
  546. return (const struct ast_aoc_s_entry *) &decoded->aoc_s_entries[entry_number];
  547. }
  548. int ast_aoc_s_add_rate_duration(struct ast_aoc_decoded *decoded,
  549. enum ast_aoc_s_charged_item charged_item,
  550. unsigned int amount,
  551. enum ast_aoc_currency_multiplier multiplier,
  552. const char *currency_name,
  553. unsigned long time,
  554. enum ast_aoc_time_scale time_scale,
  555. unsigned long granularity_time,
  556. enum ast_aoc_time_scale granularity_time_scale,
  557. int step_function)
  558. {
  559. struct ast_aoc_s_entry entry = { 0, };
  560. entry.charged_item = charged_item;
  561. entry.rate_type = AST_AOC_RATE_TYPE_DURATION;
  562. entry.rate.duration.amount = amount;
  563. entry.rate.duration.multiplier = multiplier;
  564. entry.rate.duration.time = time;
  565. entry.rate.duration.time_scale = time_scale;
  566. entry.rate.duration.granularity_time = granularity_time;
  567. entry.rate.duration.granularity_time_scale = granularity_time_scale;
  568. entry.rate.duration.charging_type = step_function ? 1 : 0;
  569. if (!ast_strlen_zero(currency_name)) {
  570. ast_copy_string(entry.rate.duration.currency_name, currency_name, sizeof(entry.rate.duration.currency_name));
  571. }
  572. return aoc_s_add_entry(decoded, &entry);
  573. }
  574. int ast_aoc_s_add_rate_flat(struct ast_aoc_decoded *decoded,
  575. enum ast_aoc_s_charged_item charged_item,
  576. unsigned int amount,
  577. enum ast_aoc_currency_multiplier multiplier,
  578. const char *currency_name)
  579. {
  580. struct ast_aoc_s_entry entry = { 0, };
  581. entry.charged_item = charged_item;
  582. entry.rate_type = AST_AOC_RATE_TYPE_FLAT;
  583. entry.rate.flat.amount = amount;
  584. entry.rate.flat.multiplier = multiplier;
  585. if (!ast_strlen_zero(currency_name)) {
  586. ast_copy_string(entry.rate.flat.currency_name, currency_name, sizeof(entry.rate.flat.currency_name));
  587. }
  588. return aoc_s_add_entry(decoded, &entry);
  589. }
  590. int ast_aoc_s_add_rate_volume(struct ast_aoc_decoded *decoded,
  591. enum ast_aoc_s_charged_item charged_item,
  592. enum ast_aoc_volume_unit volume_unit,
  593. unsigned int amount,
  594. enum ast_aoc_currency_multiplier multiplier,
  595. const char *currency_name)
  596. {
  597. struct ast_aoc_s_entry entry = { 0, };
  598. entry.charged_item = charged_item;
  599. entry.rate_type = AST_AOC_RATE_TYPE_VOLUME;
  600. entry.rate.volume.multiplier = multiplier;
  601. entry.rate.volume.amount = amount;
  602. entry.rate.volume.volume_unit = volume_unit;
  603. if (!ast_strlen_zero(currency_name)) {
  604. ast_copy_string(entry.rate.volume.currency_name, currency_name, sizeof(entry.rate.volume.currency_name));
  605. }
  606. return aoc_s_add_entry(decoded, &entry);
  607. }
  608. int ast_aoc_s_add_rate_special_charge_code(struct ast_aoc_decoded *decoded,
  609. enum ast_aoc_s_charged_item charged_item,
  610. unsigned int code)
  611. {
  612. struct ast_aoc_s_entry entry = { 0, };
  613. entry.charged_item = charged_item;
  614. entry.rate_type = AST_AOC_RATE_TYPE_SPECIAL_CODE;
  615. entry.rate.special_code = code;
  616. return aoc_s_add_entry(decoded, &entry);
  617. }
  618. int ast_aoc_s_add_rate_free(struct ast_aoc_decoded *decoded,
  619. enum ast_aoc_s_charged_item charged_item,
  620. int from_beginning)
  621. {
  622. struct ast_aoc_s_entry entry = { 0, };
  623. entry.charged_item = charged_item;
  624. entry.rate_type = from_beginning ? AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING : AST_AOC_RATE_TYPE_FREE;
  625. return aoc_s_add_entry(decoded, &entry);
  626. }
  627. int ast_aoc_s_add_rate_na(struct ast_aoc_decoded *decoded,
  628. enum ast_aoc_s_charged_item charged_item)
  629. {
  630. struct ast_aoc_s_entry entry = { 0, };
  631. entry.charged_item = charged_item;
  632. entry.rate_type = AST_AOC_RATE_TYPE_NA;
  633. return aoc_s_add_entry(decoded, &entry);
  634. }
  635. int ast_aoc_s_add_special_arrangement(struct ast_aoc_decoded *decoded,
  636. unsigned int code)
  637. {
  638. struct ast_aoc_s_entry entry = { 0, };
  639. entry.charged_item = AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
  640. entry.rate_type = AST_AOC_RATE_TYPE_SPECIAL_CODE;
  641. entry.rate.special_code = code;
  642. return aoc_s_add_entry(decoded, &entry);
  643. }
  644. enum ast_aoc_type ast_aoc_get_msg_type(struct ast_aoc_decoded *decoded)
  645. {
  646. return decoded->msg_type;
  647. }
  648. enum ast_aoc_charge_type ast_aoc_get_charge_type(struct ast_aoc_decoded *decoded)
  649. {
  650. return decoded->charge_type;
  651. }
  652. enum ast_aoc_request ast_aoc_get_request(struct ast_aoc_decoded *decoded)
  653. {
  654. return decoded->request_flag;
  655. }
  656. int ast_aoc_set_total_type(struct ast_aoc_decoded *decoded,
  657. const enum ast_aoc_total_type type)
  658. {
  659. decoded->total_type = type;
  660. return 0;
  661. }
  662. enum ast_aoc_total_type ast_aoc_get_total_type(struct ast_aoc_decoded *decoded)
  663. {
  664. return decoded->total_type;
  665. }
  666. int ast_aoc_set_currency_info(struct ast_aoc_decoded *decoded,
  667. const unsigned int amount,
  668. const enum ast_aoc_currency_multiplier multiplier,
  669. const char *name)
  670. {
  671. if (!ast_strlen_zero(name)) {
  672. ast_copy_string(decoded->currency_name, name, sizeof(decoded->currency_name));
  673. }
  674. decoded->currency_amount = amount;
  675. if (multiplier && (multiplier < AST_AOC_MULT_NUM_ENTRIES)) {
  676. decoded->multiplier = multiplier;
  677. } else {
  678. decoded->multiplier = AST_AOC_MULT_ONE;
  679. }
  680. return 0;
  681. }
  682. unsigned int ast_aoc_get_currency_amount(struct ast_aoc_decoded *decoded)
  683. {
  684. return decoded->currency_amount;
  685. }
  686. enum ast_aoc_currency_multiplier ast_aoc_get_currency_multiplier(struct ast_aoc_decoded *decoded)
  687. {
  688. return decoded->multiplier;
  689. }
  690. const char *ast_aoc_get_currency_multiplier_decimal(struct ast_aoc_decoded *decoded)
  691. {
  692. switch (decoded->multiplier) {
  693. case AST_AOC_MULT_ONETHOUSANDTH:
  694. return "0.001";
  695. case AST_AOC_MULT_ONEHUNDREDTH:
  696. return "0.01";
  697. case AST_AOC_MULT_ONETENTH:
  698. return "0.1";
  699. case AST_AOC_MULT_ONE:
  700. return "1.0";
  701. case AST_AOC_MULT_TEN:
  702. return "10.0";
  703. case AST_AOC_MULT_HUNDRED:
  704. return "100.0";
  705. case AST_AOC_MULT_THOUSAND:
  706. return "1000.0";
  707. default:
  708. return "1.0";
  709. }
  710. }
  711. const char *ast_aoc_get_currency_name(struct ast_aoc_decoded *decoded)
  712. {
  713. return decoded->currency_name;
  714. }
  715. int ast_aoc_add_unit_entry(struct ast_aoc_decoded *decoded,
  716. const unsigned int amount_is_present,
  717. const unsigned int amount,
  718. const unsigned int type_is_present,
  719. const unsigned int type)
  720. {
  721. if ((decoded->msg_type == AST_AOC_REQUEST) ||
  722. (decoded->unit_count >= ARRAY_LEN(decoded->unit_list))) {
  723. return -1;
  724. }
  725. if (!amount_is_present && !type_is_present) {
  726. return -1;
  727. }
  728. decoded->unit_list[decoded->unit_count].valid_amount = amount_is_present;
  729. if (amount_is_present) {
  730. decoded->unit_list[decoded->unit_count].amount = amount;
  731. } else {
  732. decoded->unit_list[decoded->unit_count].amount = 0;
  733. }
  734. decoded->unit_list[decoded->unit_count].valid_type = type_is_present;
  735. if (type_is_present) {
  736. decoded->unit_list[decoded->unit_count].type = type;
  737. } else {
  738. decoded->unit_list[decoded->unit_count].type = 0;
  739. }
  740. decoded->unit_count++;
  741. return 0;
  742. }
  743. const struct ast_aoc_unit_entry *ast_aoc_get_unit_info(struct ast_aoc_decoded *decoded, unsigned int entry_number)
  744. {
  745. if (entry_number >= decoded->unit_count) {
  746. return NULL;
  747. }
  748. return (const struct ast_aoc_unit_entry *) &decoded->unit_list[entry_number];
  749. }
  750. unsigned int ast_aoc_get_unit_count(struct ast_aoc_decoded *decoded)
  751. {
  752. return decoded->unit_count;
  753. }
  754. int ast_aoc_set_billing_id(struct ast_aoc_decoded *decoded, const enum ast_aoc_billing_id id)
  755. {
  756. if ((id >= AST_AOC_BILLING_NUM_ENTRIES) || (id < AST_AOC_BILLING_NA)) {
  757. return -1;
  758. }
  759. decoded->billing_id = id;
  760. return 0;
  761. }
  762. enum ast_aoc_billing_id ast_aoc_get_billing_id(struct ast_aoc_decoded *decoded)
  763. {
  764. return decoded->billing_id;
  765. }
  766. int ast_aoc_set_association_id(struct ast_aoc_decoded *decoded, const int id)
  767. {
  768. if (decoded->msg_type != AST_AOC_E) {
  769. return -1;
  770. }
  771. memset(&decoded->charging_association, 0, sizeof(decoded->charging_association));
  772. decoded->charging_association.charging_type = AST_AOC_CHARGING_ASSOCIATION_ID;
  773. decoded->charging_association.charge.id = id;
  774. return 0;
  775. }
  776. const struct ast_aoc_charging_association *ast_aoc_get_association_info(struct ast_aoc_decoded *decoded)
  777. {
  778. return &decoded->charging_association;
  779. }
  780. int ast_aoc_set_association_number(struct ast_aoc_decoded *decoded, const char *num, uint8_t plan)
  781. {
  782. if ((decoded->msg_type != AST_AOC_E) || ast_strlen_zero(num)) {
  783. return -1;
  784. }
  785. memset(&decoded->charging_association, 0, sizeof(decoded->charging_association));
  786. decoded->charging_association.charging_type = AST_AOC_CHARGING_ASSOCIATION_NUMBER;
  787. decoded->charging_association.charge.number.plan = plan;
  788. ast_copy_string(decoded->charging_association.charge.number.number, num, sizeof(decoded->charging_association.charge.number.number));
  789. return 0;
  790. }
  791. int ast_aoc_set_termination_request(struct ast_aoc_decoded *decoded)
  792. {
  793. if (decoded->msg_type != AST_AOC_REQUEST) {
  794. return -1;
  795. }
  796. decoded->termination_request = 1;
  797. return 0;
  798. }
  799. int ast_aoc_get_termination_request(struct ast_aoc_decoded *decoded)
  800. {
  801. return decoded->termination_request;
  802. }
  803. /*!
  804. * \internal
  805. * \brief Convert AST_AOC_VOLUME_UNIT to string.
  806. * \since 1.8
  807. *
  808. * \param value Value to convert to string.
  809. *
  810. * \return String equivalent.
  811. */
  812. static const char *aoc_volume_unit_str(enum ast_aoc_volume_unit value)
  813. {
  814. const char *str;
  815. switch (value) {
  816. default:
  817. case AST_AOC_VOLUME_UNIT_OCTET:
  818. str = "Octet";
  819. break;
  820. case AST_AOC_VOLUME_UNIT_SEGMENT:
  821. str = "Segment";
  822. break;
  823. case AST_AOC_VOLUME_UNIT_MESSAGE:
  824. str = "Message";
  825. break;
  826. }
  827. return str;
  828. }
  829. /*!
  830. * \internal
  831. * \brief Convert ast_aoc_charged_item to string.
  832. * \since 1.8
  833. *
  834. * \param value Value to convert to string.
  835. *
  836. * \return String equivalent.
  837. */
  838. static const char *aoc_charged_item_str(enum ast_aoc_s_charged_item value)
  839. {
  840. const char *str;
  841. switch (value) {
  842. default:
  843. case AST_AOC_CHARGED_ITEM_NA:
  844. str = "NotAvailable";
  845. break;
  846. case AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT:
  847. str = "SpecialArrangement";
  848. break;
  849. case AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION:
  850. str = "BasicCommunication";
  851. break;
  852. case AST_AOC_CHARGED_ITEM_CALL_ATTEMPT:
  853. str = "CallAttempt";
  854. break;
  855. case AST_AOC_CHARGED_ITEM_CALL_SETUP:
  856. str = "CallSetup";
  857. break;
  858. case AST_AOC_CHARGED_ITEM_USER_USER_INFO:
  859. str = "UserUserInfo";
  860. break;
  861. case AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE:
  862. str = "SupplementaryService";
  863. break;
  864. }
  865. return str;
  866. }
  867. /*!
  868. * \internal
  869. * \brief Convert ast_aoc_total_type to string.
  870. * \since 1.8
  871. *
  872. * \param value Value to convert to string.
  873. *
  874. * \return String equivalent.
  875. */
  876. static const char *aoc_type_of_totaling_str(enum ast_aoc_total_type value)
  877. {
  878. const char *str;
  879. switch (value) {
  880. default:
  881. case AST_AOC_SUBTOTAL:
  882. str = "SubTotal";
  883. break;
  884. case AST_AOC_TOTAL:
  885. str = "Total";
  886. break;
  887. }
  888. return str;
  889. }
  890. /*!
  891. * \internal
  892. * \brief Convert ast_aoc_rate_type to string.
  893. * \since 1.8
  894. *
  895. * \param value Value to convert to string.
  896. *
  897. * \return String equivalent.
  898. */
  899. static const char *aoc_rate_type_str(enum ast_aoc_s_rate_type value)
  900. {
  901. const char *str;
  902. switch (value) {
  903. default:
  904. case AST_AOC_RATE_TYPE_NA:
  905. str = "NotAvailable";
  906. break;
  907. case AST_AOC_RATE_TYPE_FREE:
  908. str = "Free";
  909. break;
  910. case AST_AOC_RATE_TYPE_FREE_FROM_BEGINNING:
  911. str = "FreeFromBeginning";
  912. break;
  913. case AST_AOC_RATE_TYPE_DURATION:
  914. str = "Duration";
  915. break;
  916. case AST_AOC_RATE_TYPE_FLAT:
  917. str = "Flat";
  918. break;
  919. case AST_AOC_RATE_TYPE_VOLUME:
  920. str = "Volume";
  921. break;
  922. case AST_AOC_RATE_TYPE_SPECIAL_CODE:
  923. str = "SpecialCode";
  924. break;
  925. }
  926. return str;
  927. }
  928. /*!
  929. * \internal
  930. * \brief Convert AST_AOC_TIME_SCALE to string.
  931. * \since 1.8
  932. *
  933. * \param value Value to convert to string.
  934. *
  935. * \return String equivalent.
  936. */
  937. static const char *aoc_scale_str(enum ast_aoc_time_scale value)
  938. {
  939. const char *str;
  940. switch (value) {
  941. default:
  942. case AST_AOC_TIME_SCALE_HUNDREDTH_SECOND:
  943. str = "OneHundredthSecond";
  944. break;
  945. case AST_AOC_TIME_SCALE_TENTH_SECOND:
  946. str = "OneTenthSecond";
  947. break;
  948. case AST_AOC_TIME_SCALE_SECOND:
  949. str = "Second";
  950. break;
  951. case AST_AOC_TIME_SCALE_TEN_SECOND:
  952. str = "TenSeconds";
  953. break;
  954. case AST_AOC_TIME_SCALE_MINUTE:
  955. str = "Minute";
  956. break;
  957. case AST_AOC_TIME_SCALE_HOUR:
  958. str = "Hour";
  959. break;
  960. case AST_AOC_TIME_SCALE_DAY:
  961. str = "Day";
  962. break;
  963. }
  964. return str;
  965. }
  966. static const char *aoc_charge_type_str(enum ast_aoc_charge_type value)
  967. {
  968. const char *str;
  969. switch (value) {
  970. default:
  971. case AST_AOC_CHARGE_NA:
  972. str = "NotAvailable";
  973. break;
  974. case AST_AOC_CHARGE_FREE:
  975. str = "Free";
  976. break;
  977. case AST_AOC_CHARGE_CURRENCY:
  978. str = "Currency";
  979. break;
  980. case AST_AOC_CHARGE_UNIT:
  981. str = "Units";
  982. break;
  983. }
  984. return str;
  985. }
  986. static const char *aoc_multiplier_str(enum ast_aoc_currency_multiplier mult)
  987. {
  988. switch (mult) {
  989. case AST_AOC_MULT_ONETHOUSANDTH:
  990. return "1/1000";
  991. case AST_AOC_MULT_ONEHUNDREDTH:
  992. return "1/100";
  993. case AST_AOC_MULT_ONETENTH:
  994. return "1/10";
  995. case AST_AOC_MULT_ONE:
  996. return "1";
  997. case AST_AOC_MULT_TEN:
  998. return "10";
  999. case AST_AOC_MULT_HUNDRED:
  1000. return "100";
  1001. case AST_AOC_MULT_THOUSAND:
  1002. return "1000";
  1003. case AST_AOC_MULT_NUM_ENTRIES:
  1004. break;
  1005. }
  1006. return "1";
  1007. }
  1008. static const char *aoc_billingid_str(enum ast_aoc_billing_id billing_id)
  1009. {
  1010. switch (billing_id) {
  1011. case AST_AOC_BILLING_NORMAL:
  1012. return "Normal";
  1013. case AST_AOC_BILLING_REVERSE_CHARGE:
  1014. return "Reverse";
  1015. case AST_AOC_BILLING_CREDIT_CARD:
  1016. return "CreditCard";
  1017. case AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL:
  1018. return "CallForwardingUnconditional";
  1019. case AST_AOC_BILLING_CALL_FWD_BUSY:
  1020. return "CallForwardingBusy";
  1021. case AST_AOC_BILLING_CALL_FWD_NO_REPLY:
  1022. return "CallForwardingNoReply";
  1023. case AST_AOC_BILLING_CALL_DEFLECTION:
  1024. return "CallDeflection";
  1025. case AST_AOC_BILLING_CALL_TRANSFER:
  1026. return "CallTransfer";
  1027. case AST_AOC_BILLING_NA:
  1028. return "NotAvailable";
  1029. case AST_AOC_BILLING_NUM_ENTRIES:
  1030. break;
  1031. }
  1032. return "NotAvailable";
  1033. }
  1034. int ast_aoc_test_encode_decode_match(struct ast_aoc_decoded *decoded)
  1035. {
  1036. struct ast_aoc_decoded *new_decoded = NULL;
  1037. struct ast_aoc_encoded *encoded = NULL;
  1038. size_t size;
  1039. int res = 0;
  1040. if (!(encoded = ast_aoc_encode(decoded, &size, NULL))) {
  1041. return -1;
  1042. }
  1043. if (!(new_decoded = ast_aoc_decode(encoded, size, NULL))) {
  1044. ast_free(encoded);
  1045. return -1;
  1046. }
  1047. if (memcmp(new_decoded, decoded, sizeof(struct ast_aoc_decoded))) {
  1048. res = -1;
  1049. }
  1050. ast_aoc_destroy_decoded(new_decoded);
  1051. ast_aoc_destroy_encoded(encoded);
  1052. return res;
  1053. }
  1054. static char *aoc_cli_debug_enable(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  1055. {
  1056. switch (cmd) {
  1057. case CLI_INIT:
  1058. e->command = "aoc set debug";
  1059. e->usage =
  1060. "Usage: 'aoc set debug on' to enable aoc debug, 'aoc set debug off' to disable debug.\n";
  1061. return NULL;
  1062. case CLI_GENERATE:
  1063. return NULL;
  1064. case CLI_HANDLER:
  1065. if (a->argc != 4) {
  1066. return CLI_SHOWUSAGE;
  1067. } else if(ast_true(a->argv[3])) {
  1068. ast_cli(a->fd, "aoc debug enabled\n");
  1069. aoc_debug_enabled = 1;
  1070. } else if (ast_false(a->argv[3])) {
  1071. ast_cli(a->fd, "aoc debug disabled\n");
  1072. aoc_debug_enabled = 0;
  1073. } else {
  1074. return CLI_SHOWUSAGE;
  1075. }
  1076. }
  1077. return CLI_SUCCESS;
  1078. }
  1079. /*!
  1080. * \internal
  1081. * \brief Append the time structure to the event message string.
  1082. * \since 1.8
  1083. *
  1084. * \param msg Event message string being built.
  1085. * \param prefix Prefix to add to the amount lines.
  1086. * \param name Name of the time structure to convert.
  1087. * \param time Data to convert.
  1088. * \param scale Data to convert.
  1089. *
  1090. * \return Nothing
  1091. */
  1092. static void aoc_time_str(struct ast_str **msg, const char *prefix, const char *name, unsigned long time, enum ast_aoc_time_scale scale)
  1093. {
  1094. ast_str_append(msg, 0, "%s/%s/Length: %lu\r\n", prefix, name, time);
  1095. ast_str_append(msg, 0, "%s/%s/Scale: %s\r\n", prefix, name,
  1096. aoc_scale_str(scale));
  1097. }
  1098. /*!
  1099. * \internal
  1100. * \brief Append the amount structure to the event message string.
  1101. * \since 1.8
  1102. *
  1103. * \param msg Event message string being built.
  1104. * \param prefix Prefix to add to the amount lines.
  1105. * \param amount Data to convert.
  1106. * \param multipler to convert
  1107. *
  1108. * \return Nothing
  1109. */
  1110. static void aoc_amount_str(struct ast_str **msg, const char *prefix, unsigned int amount, enum ast_aoc_currency_multiplier mult)
  1111. {
  1112. static const char name[] = "Amount";
  1113. ast_str_append(msg, 0, "%s/%s/Cost: %u\r\n", prefix, name, amount);
  1114. ast_str_append(msg, 0, "%s/%s/Multiplier: %s\r\n", prefix, name,
  1115. aoc_multiplier_str(mult));
  1116. }
  1117. static void aoc_request_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan, struct ast_str **msg)
  1118. {
  1119. if (chan) {
  1120. ast_str_append(msg, 0, "Channel: %s\r\n", ast_channel_name(chan));
  1121. ast_str_append(msg, 0, "UniqueID: %s\r\n", ast_channel_uniqueid(chan));
  1122. }
  1123. if (decoded->request_flag) {
  1124. ast_str_append(msg, 0, "AOCRequest:");
  1125. if (decoded->request_flag & AST_AOC_REQUEST_S) {
  1126. ast_str_append(msg, 0, "S");
  1127. }
  1128. if (decoded->request_flag & AST_AOC_REQUEST_D) {
  1129. ast_str_append(msg, 0, "D");
  1130. }
  1131. if (decoded->request_flag & AST_AOC_REQUEST_E) {
  1132. ast_str_append(msg, 0, "E");
  1133. }
  1134. ast_str_append(msg, 0, "\r\n");
  1135. } else {
  1136. ast_str_append(msg, 0, "AOCRequest: NONE\r\n");
  1137. }
  1138. }
  1139. static void aoc_s_event(const struct ast_aoc_decoded *decoded, struct ast_channel *owner, struct ast_str **msg)
  1140. {
  1141. const char *rate_str;
  1142. char prefix[32];
  1143. int idx;
  1144. if (owner) {
  1145. ast_str_append(msg, 0, "Channel: %s\r\n", ast_channel_name(owner));
  1146. ast_str_append(msg, 0, "UniqueID: %s\r\n", ast_channel_uniqueid(owner));
  1147. }
  1148. ast_str_append(msg, 0, "NumberRates: %d\r\n", decoded->aoc_s_count);
  1149. for (idx = 0; idx < decoded->aoc_s_count; ++idx) {
  1150. snprintf(prefix, sizeof(prefix), "Rate(%d)", idx);
  1151. ast_str_append(msg, 0, "%s/Chargeable: %s\r\n", prefix,
  1152. aoc_charged_item_str(decoded->aoc_s_entries[idx].charged_item));
  1153. if (decoded->aoc_s_entries[idx].charged_item == AST_AOC_CHARGED_ITEM_NA) {
  1154. continue;
  1155. }
  1156. rate_str = aoc_rate_type_str(decoded->aoc_s_entries[idx].rate_type);
  1157. ast_str_append(msg, 0, "%s/Type: %s\r\n", prefix, rate_str);
  1158. switch (decoded->aoc_s_entries[idx].rate_type) {
  1159. case AST_AOC_RATE_TYPE_DURATION:
  1160. strcat(prefix, "/");
  1161. strcat(prefix, rate_str);
  1162. ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
  1163. decoded->aoc_s_entries[idx].rate.duration.currency_name);
  1164. aoc_amount_str(msg, prefix,
  1165. decoded->aoc_s_entries[idx].rate.duration.amount,
  1166. decoded->aoc_s_entries[idx].rate.duration.multiplier);
  1167. ast_str_append(msg, 0, "%s/ChargingType: %s\r\n", prefix,
  1168. decoded->aoc_s_entries[idx].rate.duration.charging_type ?
  1169. "StepFunction" : "ContinuousCharging");
  1170. aoc_time_str(msg, prefix, "Time",
  1171. decoded->aoc_s_entries[idx].rate.duration.time,
  1172. decoded->aoc_s_entries[idx].rate.duration.time_scale);
  1173. if (decoded->aoc_s_entries[idx].rate.duration.granularity_time) {
  1174. aoc_time_str(msg, prefix, "Granularity",
  1175. decoded->aoc_s_entries[idx].rate.duration.granularity_time,
  1176. decoded->aoc_s_entries[idx].rate.duration.granularity_time_scale);
  1177. }
  1178. break;
  1179. case AST_AOC_RATE_TYPE_FLAT:
  1180. strcat(prefix, "/");
  1181. strcat(prefix, rate_str);
  1182. ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
  1183. decoded->aoc_s_entries[idx].rate.flat.currency_name);
  1184. aoc_amount_str(msg, prefix,
  1185. decoded->aoc_s_entries[idx].rate.flat.amount,
  1186. decoded->aoc_s_entries[idx].rate.flat.multiplier);
  1187. break;
  1188. case AST_AOC_RATE_TYPE_VOLUME:
  1189. strcat(prefix, "/");
  1190. strcat(prefix, rate_str);
  1191. ast_str_append(msg, 0, "%s/Currency: %s\r\n", prefix,
  1192. decoded->aoc_s_entries[idx].rate.volume.currency_name);
  1193. aoc_amount_str(msg, prefix,
  1194. decoded->aoc_s_entries[idx].rate.volume.amount,
  1195. decoded->aoc_s_entries[idx].rate.volume.multiplier);
  1196. ast_str_append(msg, 0, "%s/Unit: %s\r\n", prefix,
  1197. aoc_volume_unit_str(decoded->aoc_s_entries[idx].rate.volume.volume_unit));
  1198. break;
  1199. case AST_AOC_RATE_TYPE_SPECIAL_CODE:
  1200. ast_str_append(msg, 0, "%s/%s: %d\r\n", prefix, rate_str,
  1201. decoded->aoc_s_entries[idx].rate.special_code);
  1202. break;
  1203. default:
  1204. break;
  1205. }
  1206. }
  1207. }
  1208. static void aoc_d_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan, struct ast_str **msg)
  1209. {
  1210. const char *charge_str;
  1211. int idx;
  1212. char prefix[32];
  1213. if (chan) {
  1214. ast_str_append(msg, 0, "Channel: %s\r\n", ast_channel_name(chan));
  1215. ast_str_append(msg, 0, "UniqueID: %s\r\n", ast_channel_uniqueid(chan));
  1216. }
  1217. charge_str = aoc_charge_type_str(decoded->charge_type);
  1218. ast_str_append(msg, 0, "Type: %s\r\n", charge_str);
  1219. switch (decoded->charge_type) {
  1220. case AST_AOC_CHARGE_CURRENCY:
  1221. case AST_AOC_CHARGE_UNIT:
  1222. ast_str_append(msg, 0, "BillingID: %s\r\n",
  1223. aoc_billingid_str(decoded->billing_id));
  1224. ast_str_append(msg, 0, "TypeOfCharging: %s\r\n",
  1225. aoc_type_of_totaling_str(decoded->total_type));
  1226. break;
  1227. default:
  1228. break;
  1229. }
  1230. switch (decoded->charge_type) {
  1231. case AST_AOC_CHARGE_CURRENCY:
  1232. ast_str_append(msg, 0, "%s: %s\r\n", charge_str,
  1233. decoded->currency_name);
  1234. aoc_amount_str(msg, charge_str,
  1235. decoded->currency_amount,
  1236. decoded->multiplier);
  1237. break;
  1238. case AST_AOC_CHARGE_UNIT:
  1239. ast_str_append(msg, 0, "%s/NumberItems: %d\r\n", charge_str,
  1240. decoded->unit_count);
  1241. for (idx = 0; idx < decoded->unit_count; ++idx) {
  1242. snprintf(prefix, sizeof(prefix), "%s/Item(%d)", charge_str, idx);
  1243. if (decoded->unit_list[idx].valid_amount) {
  1244. ast_str_append(msg, 0, "%s/NumberOf: %u\r\n", prefix,
  1245. decoded->unit_list[idx].amount);
  1246. }
  1247. if (decoded->unit_list[idx].valid_type) {
  1248. ast_str_append(msg, 0, "%s/TypeOf: %u\r\n", prefix,
  1249. decoded->unit_list[idx].type);
  1250. }
  1251. }
  1252. break;
  1253. default:
  1254. break;
  1255. }
  1256. }
  1257. static void aoc_e_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan, struct ast_str **msg)
  1258. {
  1259. const char *charge_str;
  1260. int idx;
  1261. char prefix[32];
  1262. if (chan) {
  1263. ast_str_append(msg, 0, "Channel: %s\r\n", ast_channel_name(chan));
  1264. ast_str_append(msg, 0, "UniqueID: %s\r\n", ast_channel_uniqueid(chan));
  1265. }
  1266. charge_str = "ChargingAssociation";
  1267. switch (decoded->charging_association.charging_type) {
  1268. case AST_AOC_CHARGING_ASSOCIATION_NUMBER:
  1269. snprintf(prefix, sizeof(prefix), "%s/Number", charge_str);
  1270. ast_str_append(msg, 0, "%s: %s\r\n", prefix,
  1271. decoded->charging_association.charge.number.number);
  1272. ast_str_append(msg, 0, "%s/Plan: %d\r\n", prefix,
  1273. decoded->charging_association.charge.number.plan);
  1274. break;
  1275. case AST_AOC_CHARGING_ASSOCIATION_ID:
  1276. ast_str_append(msg, 0, "%s/ID: %d\r\n", charge_str, decoded->charging_association.charge.id);
  1277. break;
  1278. case AST_AOC_CHARGING_ASSOCIATION_NA:
  1279. default:
  1280. break;
  1281. }
  1282. charge_str = aoc_charge_type_str(decoded->charge_type);
  1283. ast_str_append(msg, 0, "Type: %s\r\n", charge_str);
  1284. switch (decoded->charge_type) {
  1285. case AST_AOC_CHARGE_CURRENCY:
  1286. case AST_AOC_CHARGE_UNIT:
  1287. ast_str_append(msg, 0, "BillingID: %s\r\n",
  1288. aoc_billingid_str(decoded->billing_id));
  1289. break;
  1290. default:
  1291. break;
  1292. }
  1293. switch (decoded->charge_type) {
  1294. case AST_AOC_CHARGE_CURRENCY:
  1295. ast_str_append(msg, 0, "%s: %s\r\n", charge_str,
  1296. decoded->currency_name);
  1297. aoc_amount_str(msg, charge_str,
  1298. decoded->currency_amount,
  1299. decoded->multiplier);
  1300. break;
  1301. case AST_AOC_CHARGE_UNIT:
  1302. ast_str_append(msg, 0, "%s/NumberItems: %d\r\n", charge_str,
  1303. decoded->unit_count);
  1304. for (idx = 0; idx < decoded->unit_count; ++idx) {
  1305. snprintf(prefix, sizeof(prefix), "%s/Item(%d)", charge_str, idx);
  1306. if (decoded->unit_list[idx].valid_amount) {
  1307. ast_str_append(msg, 0, "%s/NumberOf: %u\r\n", prefix,
  1308. decoded->unit_list[idx].amount);
  1309. }
  1310. if (decoded->unit_list[idx].valid_type) {
  1311. ast_str_append(msg, 0, "%s/TypeOf: %u\r\n", prefix,
  1312. decoded->unit_list[idx].type);
  1313. }
  1314. }
  1315. break;
  1316. default:
  1317. break;
  1318. }
  1319. }
  1320. int ast_aoc_manager_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan)
  1321. {
  1322. struct ast_str *msg;
  1323. if (!decoded || !(msg = ast_str_create(1024))) {
  1324. return -1;
  1325. }
  1326. switch (decoded->msg_type) {
  1327. case AST_AOC_S:
  1328. if (chan) {
  1329. aoc_s_event(decoded, chan, &msg);
  1330. ast_manager_event(chan, EVENT_FLAG_AOC, "AOC-S", "%s", ast_str_buffer(msg));
  1331. }
  1332. break;
  1333. case AST_AOC_D:
  1334. if (chan) {
  1335. aoc_d_event(decoded, chan, &msg);
  1336. ast_manager_event(chan, EVENT_FLAG_AOC, "AOC-D", "%s", ast_str_buffer(msg));
  1337. }
  1338. break;
  1339. case AST_AOC_E:
  1340. {
  1341. struct ast_channel *chans[1];
  1342. aoc_e_event(decoded, chan, &msg);
  1343. chans[0] = chan;
  1344. ast_manager_event_multichan(EVENT_FLAG_AOC, "AOC-E", chan ? 1 : 0, chans, "%s", ast_str_buffer(msg));
  1345. }
  1346. break;
  1347. default:
  1348. /* events for AST_AOC_REQUEST are not generated here */
  1349. break;
  1350. }
  1351. ast_free(msg);
  1352. return 0;
  1353. }
  1354. int ast_aoc_decoded2str(const struct ast_aoc_decoded *decoded, struct ast_str **msg)
  1355. {
  1356. if (!decoded || !msg) {
  1357. return -1;
  1358. }
  1359. switch (decoded->msg_type) {
  1360. case AST_AOC_S:
  1361. ast_str_append(msg, 0, "AOC-S\r\n");
  1362. aoc_s_event(decoded, NULL, msg);
  1363. break;
  1364. case AST_AOC_D:
  1365. ast_str_append(msg, 0, "AOC-D\r\n");
  1366. aoc_d_event(decoded, NULL, msg);
  1367. break;
  1368. case AST_AOC_E:
  1369. ast_str_append(msg, 0, "AOC-E\r\n");
  1370. aoc_e_event(decoded, NULL, msg);
  1371. break;
  1372. case AST_AOC_REQUEST:
  1373. ast_str_append(msg, 0, "AOC-Request\r\n");
  1374. aoc_request_event(decoded, NULL, msg);
  1375. break;
  1376. }
  1377. return 0;
  1378. }
  1379. static void aoc_display_decoded_debug(const struct ast_aoc_decoded *decoded, int decoding, struct ast_channel *chan)
  1380. {
  1381. struct ast_str *msg;
  1382. if (!decoded || !(msg = ast_str_create(1024))) {
  1383. return;
  1384. }
  1385. if (decoding) {
  1386. ast_str_append(&msg, 0, "---- DECODED AOC MSG ----\r\n");
  1387. } else {
  1388. ast_str_append(&msg, 0, "---- ENCODED AOC MSG ----\r\n");
  1389. }
  1390. if (chan) {
  1391. ast_str_append(&msg, 0, "CHANNEL: %s\r\n", ast_channel_name(chan));
  1392. }
  1393. if (ast_aoc_decoded2str(decoded, &msg)) {
  1394. ast_free(msg);
  1395. return;
  1396. }
  1397. ast_verb(1, "%s\r\n", ast_str_buffer(msg));
  1398. ast_free(msg);
  1399. }
  1400. static struct ast_cli_entry aoc_cli[] = {
  1401. AST_CLI_DEFINE(aoc_cli_debug_enable, "enable cli debugging of AOC messages"),
  1402. };
  1403. static void aoc_shutdown(void)
  1404. {
  1405. ast_cli_unregister_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
  1406. }
  1407. int ast_aoc_cli_init(void)
  1408. {
  1409. ast_register_cleanup(aoc_shutdown);
  1410. return ast_cli_register_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
  1411. }