func_db.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2005-2006, Russell Bryant <russelb@clemson.edu>
  5. *
  6. * func_db.c adapted from the old app_db.c, copyright by the following people
  7. * Copyright (C) 2005, Mark Spencer <markster@digium.com>
  8. * Copyright (C) 2003, Jefferson Noxon <jeff@debian.org>
  9. *
  10. * See http://www.asterisk.org for more information about
  11. * the Asterisk project. Please do not directly contact
  12. * any of the maintainers of this project for assistance;
  13. * the project provides a web site, mailing lists and IRC
  14. * channels for your use.
  15. *
  16. * This program is free software, distributed under the terms of
  17. * the GNU General Public License Version 2. See the LICENSE file
  18. * at the top of the source tree.
  19. */
  20. /*! \file
  21. *
  22. * \brief Functions for interaction with the Asterisk database
  23. *
  24. * \author Russell Bryant <russelb@clemson.edu>
  25. *
  26. * \ingroup functions
  27. */
  28. /*** MODULEINFO
  29. <support_level>core</support_level>
  30. ***/
  31. #include "asterisk.h"
  32. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  33. #include <regex.h>
  34. #include "asterisk/module.h"
  35. #include "asterisk/channel.h"
  36. #include "asterisk/pbx.h"
  37. #include "asterisk/utils.h"
  38. #include "asterisk/app.h"
  39. #include "asterisk/astdb.h"
  40. /*** DOCUMENTATION
  41. <function name="DB" language="en_US">
  42. <synopsis>
  43. Read from or write to the Asterisk database.
  44. </synopsis>
  45. <syntax argsep="/">
  46. <parameter name="family" required="true" />
  47. <parameter name="key" required="true" />
  48. </syntax>
  49. <description>
  50. <para>This function will read from or write a value to the Asterisk database. On a
  51. read, this function returns the corresponding value from the database, or blank
  52. if it does not exist. Reading a database value will also set the variable
  53. DB_RESULT. If you wish to find out if an entry exists, use the DB_EXISTS
  54. function.</para>
  55. </description>
  56. <see-also>
  57. <ref type="application">DBdel</ref>
  58. <ref type="function">DB_DELETE</ref>
  59. <ref type="application">DBdeltree</ref>
  60. <ref type="function">DB_EXISTS</ref>
  61. </see-also>
  62. </function>
  63. <function name="DB_EXISTS" language="en_US">
  64. <synopsis>
  65. Check to see if a key exists in the Asterisk database.
  66. </synopsis>
  67. <syntax argsep="/">
  68. <parameter name="family" required="true" />
  69. <parameter name="key" required="true" />
  70. </syntax>
  71. <description>
  72. <para>This function will check to see if a key exists in the Asterisk
  73. database. If it exists, the function will return <literal>1</literal>. If not,
  74. it will return <literal>0</literal>. Checking for existence of a database key will
  75. also set the variable DB_RESULT to the key's value if it exists.</para>
  76. </description>
  77. <see-also>
  78. <ref type="function">DB</ref>
  79. </see-also>
  80. </function>
  81. <function name="DB_KEYS" language="en_US">
  82. <synopsis>
  83. Obtain a list of keys within the Asterisk database.
  84. </synopsis>
  85. <syntax>
  86. <parameter name="prefix" />
  87. </syntax>
  88. <description>
  89. <para>This function will return a comma-separated list of keys existing
  90. at the prefix specified within the Asterisk database. If no argument is
  91. provided, then a list of key families will be returned.</para>
  92. </description>
  93. </function>
  94. <function name="DB_DELETE" language="en_US">
  95. <synopsis>
  96. Return a value from the database and delete it.
  97. </synopsis>
  98. <syntax argsep="/">
  99. <parameter name="family" required="true" />
  100. <parameter name="key" required="true" />
  101. </syntax>
  102. <description>
  103. <para>This function will retrieve a value from the Asterisk database
  104. and then remove that key from the database. <variable>DB_RESULT</variable>
  105. will be set to the key's value if it exists.</para>
  106. <note>
  107. <para>If <literal>live_dangerously</literal> in <literal>asterisk.conf</literal>
  108. is set to <literal>no</literal>, this function can only be read from the
  109. dialplan, and not directly from external protocols. It can, however, be
  110. executed as a write operation (<literal>DB_DELETE(family, key)=ignored</literal>)</para>
  111. </note>
  112. </description>
  113. <see-also>
  114. <ref type="application">DBdel</ref>
  115. <ref type="function">DB</ref>
  116. <ref type="application">DBdeltree</ref>
  117. </see-also>
  118. </function>
  119. ***/
  120. static int function_db_read(struct ast_channel *chan, const char *cmd,
  121. char *parse, char *buf, size_t len)
  122. {
  123. AST_DECLARE_APP_ARGS(args,
  124. AST_APP_ARG(family);
  125. AST_APP_ARG(key);
  126. );
  127. buf[0] = '\0';
  128. if (ast_strlen_zero(parse)) {
  129. ast_log(LOG_WARNING, "DB requires an argument, DB(<family>/<key>)\n");
  130. return -1;
  131. }
  132. AST_NONSTANDARD_APP_ARGS(args, parse, '/');
  133. if (args.argc < 2) {
  134. ast_log(LOG_WARNING, "DB requires an argument, DB(<family>/<key>)\n");
  135. return -1;
  136. }
  137. if (ast_db_get(args.family, args.key, buf, len - 1)) {
  138. ast_debug(1, "DB: %s/%s not found in database.\n", args.family, args.key);
  139. } else {
  140. pbx_builtin_setvar_helper(chan, "DB_RESULT", buf);
  141. }
  142. return 0;
  143. }
  144. static int function_db_write(struct ast_channel *chan, const char *cmd, char *parse,
  145. const char *value)
  146. {
  147. AST_DECLARE_APP_ARGS(args,
  148. AST_APP_ARG(family);
  149. AST_APP_ARG(key);
  150. );
  151. if (ast_strlen_zero(parse)) {
  152. ast_log(LOG_WARNING, "DB requires an argument, DB(<family>/<key>)=<value>\n");
  153. return -1;
  154. }
  155. AST_NONSTANDARD_APP_ARGS(args, parse, '/');
  156. if (args.argc < 2) {
  157. ast_log(LOG_WARNING, "DB requires an argument, DB(<family>/<key>)=value\n");
  158. return -1;
  159. }
  160. if (ast_db_put(args.family, args.key, value)) {
  161. ast_log(LOG_WARNING, "DB: Error writing value to database.\n");
  162. }
  163. return 0;
  164. }
  165. static struct ast_custom_function db_function = {
  166. .name = "DB",
  167. .read = function_db_read,
  168. .write = function_db_write,
  169. };
  170. static int function_db_exists(struct ast_channel *chan, const char *cmd,
  171. char *parse, char *buf, size_t len)
  172. {
  173. AST_DECLARE_APP_ARGS(args,
  174. AST_APP_ARG(family);
  175. AST_APP_ARG(key);
  176. );
  177. buf[0] = '\0';
  178. if (ast_strlen_zero(parse)) {
  179. ast_log(LOG_WARNING, "DB_EXISTS requires an argument, DB(<family>/<key>)\n");
  180. return -1;
  181. }
  182. AST_NONSTANDARD_APP_ARGS(args, parse, '/');
  183. if (args.argc < 2) {
  184. ast_log(LOG_WARNING, "DB_EXISTS requires an argument, DB(<family>/<key>)\n");
  185. return -1;
  186. }
  187. if (ast_db_get(args.family, args.key, buf, len - 1)) {
  188. strcpy(buf, "0");
  189. } else {
  190. pbx_builtin_setvar_helper(chan, "DB_RESULT", buf);
  191. strcpy(buf, "1");
  192. }
  193. return 0;
  194. }
  195. static struct ast_custom_function db_exists_function = {
  196. .name = "DB_EXISTS",
  197. .read = function_db_exists,
  198. .read_max = 2,
  199. };
  200. static int function_db_keys(struct ast_channel *chan, const char *cmd, char *parse, struct ast_str **result, ssize_t maxlen)
  201. {
  202. size_t parselen = strlen(parse);
  203. struct ast_db_entry *dbe, *orig_dbe;
  204. struct ast_str *escape_buf = NULL;
  205. const char *last = "";
  206. /* Remove leading and trailing slashes */
  207. while (parse[0] == '/') {
  208. parse++;
  209. parselen--;
  210. }
  211. while (parse[parselen - 1] == '/') {
  212. parse[--parselen] = '\0';
  213. }
  214. ast_str_reset(*result);
  215. /* Nothing within the database at that prefix? */
  216. if (!(orig_dbe = dbe = ast_db_gettree(parse, NULL))) {
  217. return 0;
  218. }
  219. for (; dbe; dbe = dbe->next) {
  220. /* Find the current component */
  221. char *curkey = &dbe->key[parselen + 1], *slash;
  222. if (*curkey == '/') {
  223. curkey++;
  224. }
  225. /* Remove everything after the current component */
  226. if ((slash = strchr(curkey, '/'))) {
  227. *slash = '\0';
  228. }
  229. /* Skip duplicates */
  230. if (!strcasecmp(last, curkey)) {
  231. continue;
  232. }
  233. last = curkey;
  234. if (orig_dbe != dbe) {
  235. ast_str_append(result, maxlen, ",");
  236. }
  237. ast_str_append_escapecommas(result, maxlen, curkey, strlen(curkey));
  238. }
  239. ast_db_freetree(orig_dbe);
  240. ast_free(escape_buf);
  241. return 0;
  242. }
  243. static struct ast_custom_function db_keys_function = {
  244. .name = "DB_KEYS",
  245. .read2 = function_db_keys,
  246. };
  247. static int function_db_delete(struct ast_channel *chan, const char *cmd,
  248. char *parse, char *buf, size_t len)
  249. {
  250. AST_DECLARE_APP_ARGS(args,
  251. AST_APP_ARG(family);
  252. AST_APP_ARG(key);
  253. );
  254. buf[0] = '\0';
  255. if (ast_strlen_zero(parse)) {
  256. ast_log(LOG_WARNING, "DB_DELETE requires an argument, DB_DELETE(<family>/<key>)\n");
  257. return -1;
  258. }
  259. AST_NONSTANDARD_APP_ARGS(args, parse, '/');
  260. if (args.argc < 2) {
  261. ast_log(LOG_WARNING, "DB_DELETE requires an argument, DB_DELETE(<family>/<key>)\n");
  262. return -1;
  263. }
  264. if (ast_db_get(args.family, args.key, buf, len - 1)) {
  265. ast_debug(1, "DB_DELETE: %s/%s not found in database.\n", args.family, args.key);
  266. } else {
  267. if (ast_db_del(args.family, args.key)) {
  268. ast_debug(1, "DB_DELETE: %s/%s could not be deleted from the database\n", args.family, args.key);
  269. }
  270. }
  271. pbx_builtin_setvar_helper(chan, "DB_RESULT", buf);
  272. return 0;
  273. }
  274. /*!
  275. * \brief Wrapper to execute DB_DELETE from a write operation. Allows execution
  276. * even if live_dangerously is disabled.
  277. */
  278. static int function_db_delete_write(struct ast_channel *chan, const char *cmd, char *parse,
  279. const char *value)
  280. {
  281. /* Throwaway to hold the result from the read */
  282. char buf[128];
  283. return function_db_delete(chan, cmd, parse, buf, sizeof(buf));
  284. }
  285. static struct ast_custom_function db_delete_function = {
  286. .name = "DB_DELETE",
  287. .read = function_db_delete,
  288. .write = function_db_delete_write,
  289. };
  290. static int unload_module(void)
  291. {
  292. int res = 0;
  293. res |= ast_custom_function_unregister(&db_function);
  294. res |= ast_custom_function_unregister(&db_exists_function);
  295. res |= ast_custom_function_unregister(&db_delete_function);
  296. res |= ast_custom_function_unregister(&db_keys_function);
  297. return res;
  298. }
  299. static int load_module(void)
  300. {
  301. int res = 0;
  302. res |= ast_custom_function_register_escalating(&db_function, AST_CFE_BOTH);
  303. res |= ast_custom_function_register(&db_exists_function);
  304. res |= ast_custom_function_register_escalating(&db_delete_function, AST_CFE_READ);
  305. res |= ast_custom_function_register(&db_keys_function);
  306. return res;
  307. }
  308. AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Database (astdb) related dialplan functions");