Asterisk - The Open Source Telephony Project  21.4.1
func_db.c
Go to the documentation of this file.
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 
21 /*! \file
22  *
23  * \brief Functions for interaction with the Asterisk database
24  *
25  * \author Russell Bryant <russelb@clemson.edu>
26  *
27  * \ingroup functions
28  */
29 
30 /*** MODULEINFO
31  <support_level>core</support_level>
32  ***/
33 
34 #include "asterisk.h"
35 
36 #include <regex.h>
37 
38 #include "asterisk/module.h"
39 #include "asterisk/channel.h"
40 #include "asterisk/pbx.h"
41 #include "asterisk/utils.h"
42 #include "asterisk/app.h"
43 #include "asterisk/astdb.h"
44 
45 /*** DOCUMENTATION
46  <function name="DB" language="en_US">
47  <synopsis>
48  Read from or write to the Asterisk database.
49  </synopsis>
50  <syntax argsep="/">
51  <parameter name="family" required="true" />
52  <parameter name="key" required="true" />
53  </syntax>
54  <description>
55  <para>This function will read from or write a value to the Asterisk database. On a
56  read, this function returns the corresponding value from the database, or blank
57  if it does not exist. Reading a database value will also set the variable
58  DB_RESULT. If you wish to find out if an entry exists, use the DB_EXISTS
59  function.</para>
60  </description>
61  <see-also>
62  <ref type="application">DBdel</ref>
63  <ref type="function">DB_DELETE</ref>
64  <ref type="application">DBdeltree</ref>
65  <ref type="function">DB_EXISTS</ref>
66  </see-also>
67  </function>
68  <function name="DB_EXISTS" language="en_US">
69  <synopsis>
70  Check to see if a key exists in the Asterisk database.
71  </synopsis>
72  <syntax argsep="/">
73  <parameter name="family" required="true" />
74  <parameter name="key" required="true" />
75  </syntax>
76  <description>
77  <para>This function will check to see if a key exists in the Asterisk
78  database. If it exists, the function will return <literal>1</literal>. If not,
79  it will return <literal>0</literal>. Checking for existence of a database key will
80  also set the variable DB_RESULT to the key's value if it exists.</para>
81  </description>
82  <see-also>
83  <ref type="function">DB</ref>
84  </see-also>
85  </function>
86  <function name="DB_KEYS" language="en_US">
87  <synopsis>
88  Obtain a list of keys within the Asterisk database.
89  </synopsis>
90  <syntax>
91  <parameter name="prefix" />
92  </syntax>
93  <description>
94  <para>This function will return a comma-separated list of keys existing
95  at the prefix specified within the Asterisk database. If no argument is
96  provided, then a list of key families will be returned.</para>
97  </description>
98  <see-also>
99  <ref type="function">DB_KEYCOUNT</ref>
100  </see-also>
101  </function>
102  <function name="DB_KEYCOUNT" language="en_US">
103  <synopsis>
104  Obtain the number of keys at a prefix within the Asterisk database.
105  </synopsis>
106  <syntax>
107  <parameter name="prefix" />
108  </syntax>
109  <description>
110  <para>This function will return the number of keys that exist
111  at the prefix specified within the Asterisk database. If no argument is
112  provided, then the number of all key families will be returned.</para>
113  </description>
114  <see-also>
115  <ref type="function">DB_KEYS</ref>
116  </see-also>
117  </function>
118  <function name="DB_DELETE" language="en_US">
119  <synopsis>
120  Return a value from the database and delete it.
121  </synopsis>
122  <syntax argsep="/">
123  <parameter name="family" required="true" />
124  <parameter name="key" required="true" />
125  </syntax>
126  <description>
127  <para>This function will retrieve a value from the Asterisk database
128  and then remove that key from the database. <variable>DB_RESULT</variable>
129  will be set to the key's value if it exists.</para>
130  <note>
131  <para>If <literal>live_dangerously</literal> in <literal>asterisk.conf</literal>
132  is set to <literal>no</literal>, this function can only be read from the
133  dialplan, and not directly from external protocols. It can, however, be
134  executed as a write operation (<literal>DB_DELETE(family, key)=ignored</literal>)</para>
135  </note>
136  </description>
137  <see-also>
138  <ref type="application">DBdel</ref>
139  <ref type="function">DB</ref>
140  <ref type="application">DBdeltree</ref>
141  </see-also>
142  </function>
143  ***/
144 
145 static int function_db_read(struct ast_channel *chan, const char *cmd,
146  char *parse, char *buf, size_t len)
147 {
149  AST_APP_ARG(family);
150  AST_APP_ARG(key);
151  );
152 
153  buf[0] = '\0';
154 
155  if (ast_strlen_zero(parse)) {
156  ast_log(LOG_WARNING, "DB requires an argument, DB(<family>/<key>)\n");
157  return -1;
158  }
159 
160  AST_NONSTANDARD_APP_ARGS(args, parse, '/');
161 
162  if (args.argc < 2) {
163  ast_log(LOG_WARNING, "DB requires an argument, DB(<family>/<key>)\n");
164  return -1;
165  }
166 
167  if (ast_db_get(args.family, args.key, buf, len - 1)) {
168  ast_debug(1, "DB: %s/%s not found in database.\n", args.family, args.key);
169  } else {
170  pbx_builtin_setvar_helper(chan, "DB_RESULT", buf);
171  }
172 
173  return 0;
174 }
175 
176 static int function_db_write(struct ast_channel *chan, const char *cmd, char *parse,
177  const char *value)
178 {
180  AST_APP_ARG(family);
181  AST_APP_ARG(key);
182  );
183 
184  if (ast_strlen_zero(parse)) {
185  ast_log(LOG_WARNING, "DB requires an argument, DB(<family>/<key>)=<value>\n");
186  return -1;
187  }
188 
189  AST_NONSTANDARD_APP_ARGS(args, parse, '/');
190 
191  if (args.argc < 2) {
192  ast_log(LOG_WARNING, "DB requires an argument, DB(<family>/<key>)=value\n");
193  return -1;
194  }
195  /*
196  * When keynames are dynamically created using variables, if the variable is empty, this put bad data into the DB.
197  * In particular, a few cases: an empty key name, a key starting or ending with a /, and a key containing // two slashes.
198  * If this happens, allow it to go in, but warn the user of the issue and possible data corruption. */
199  if (ast_strlen_zero(args.key) || args.key[0] == '/' || args.key[strlen(args.key) - 1] == '/' || strstr(args.key, "//")) {
200  ast_log(LOG_WARNING, "DB: key '%s' seems malformed\n", args.key);
201  }
202  if (ast_db_put(args.family, args.key, value)) {
203  ast_log(LOG_WARNING, "DB: Error writing value to database.\n");
204  }
205 
206  return 0;
207 }
208 
209 static struct ast_custom_function db_function = {
210  .name = "DB",
211  .read = function_db_read,
212  .write = function_db_write,
213 };
214 
215 static int function_db_exists(struct ast_channel *chan, const char *cmd,
216  char *parse, char *buf, size_t len)
217 {
219  AST_APP_ARG(family);
220  AST_APP_ARG(key);
221  );
222 
223  buf[0] = '\0';
224 
225  if (ast_strlen_zero(parse)) {
226  ast_log(LOG_WARNING, "DB_EXISTS requires an argument, DB(<family>/<key>)\n");
227  return -1;
228  }
229 
230  AST_NONSTANDARD_APP_ARGS(args, parse, '/');
231 
232  if (args.argc < 2) {
233  ast_log(LOG_WARNING, "DB_EXISTS requires an argument, DB(<family>/<key>)\n");
234  return -1;
235  }
236 
237  if (ast_db_get(args.family, args.key, buf, len - 1)) {
238  strcpy(buf, "0");
239  } else {
240  pbx_builtin_setvar_helper(chan, "DB_RESULT", buf);
241  strcpy(buf, "1");
242  }
243 
244  return 0;
245 }
246 
247 static struct ast_custom_function db_exists_function = {
248  .name = "DB_EXISTS",
249  .read = function_db_exists,
250  .read_max = 2,
251 };
252 
253 static int function_db_keys(struct ast_channel *chan, const char *cmd, char *parse, struct ast_str **result, ssize_t maxlen)
254 {
255  size_t parselen = strlen(parse);
256  struct ast_db_entry *dbe, *orig_dbe;
257  struct ast_str *escape_buf = NULL;
258  const char *last = "";
259 
260  /* Remove leading and trailing slashes */
261  while (parse[0] == '/') {
262  parse++;
263  parselen--;
264  }
265  while (parse[parselen - 1] == '/') {
266  parse[--parselen] = '\0';
267  }
268 
269  ast_str_reset(*result);
270 
271  /* Nothing within the database at that prefix? */
272  if (!(orig_dbe = dbe = ast_db_gettree(parse, NULL))) {
273  return 0;
274  }
275 
276  for (; dbe; dbe = dbe->next) {
277  /* Find the current component */
278  char *curkey = &dbe->key[parselen + 1], *slash;
279  if (*curkey == '/') {
280  curkey++;
281  }
282  /* Remove everything after the current component */
283  if ((slash = strchr(curkey, '/'))) {
284  *slash = '\0';
285  }
286 
287  /* Skip duplicates */
288  if (!strcasecmp(last, curkey)) {
289  continue;
290  }
291  last = curkey;
292 
293  if (orig_dbe != dbe) {
294  ast_str_append(result, maxlen, ",");
295  }
296  ast_str_append_escapecommas(result, maxlen, curkey, strlen(curkey));
297  }
298  ast_db_freetree(orig_dbe);
299  ast_free(escape_buf);
300  return 0;
301 }
302 
303 static struct ast_custom_function db_keys_function = {
304  .name = "DB_KEYS",
305  .read2 = function_db_keys,
306 };
307 
308 static int function_db_keycount(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
309 {
310  size_t parselen = strlen(parse);
311  struct ast_db_entry *dbe, *orig_dbe;
312  const char *last = "";
313  int keycount = 0;
314 
315  /* Remove leading and trailing slashes */
316  while (parse[0] == '/') {
317  parse++;
318  parselen--;
319  }
320  while (parse[parselen - 1] == '/') {
321  parse[--parselen] = '\0';
322  }
323 
324  /* Nothing within the database at that prefix? */
325  if (!(orig_dbe = dbe = ast_db_gettree(parse, NULL))) {
326  snprintf(buf, len, "%d", keycount);
327  return 0;
328  }
329 
330  for (; dbe; dbe = dbe->next) {
331  /* Find the current component */
332  char *curkey = &dbe->key[parselen + 1], *slash;
333  if (*curkey == '/') {
334  curkey++;
335  }
336  /* Remove everything after the current component */
337  if ((slash = strchr(curkey, '/'))) {
338  *slash = '\0';
339  }
340 
341  /* Skip duplicates */
342  if (!strcasecmp(last, curkey)) {
343  continue;
344  }
345  last = curkey;
346 
347  keycount++;
348  }
349  ast_db_freetree(orig_dbe);
350  snprintf(buf, len, "%d", keycount);
351  return 0;
352 }
353 
354 static struct ast_custom_function db_keycount_function = {
355  .name = "DB_KEYCOUNT",
356  .read = function_db_keycount,
357 };
358 
359 static int function_db_delete(struct ast_channel *chan, const char *cmd,
360  char *parse, char *buf, size_t len)
361 {
363  AST_APP_ARG(family);
364  AST_APP_ARG(key);
365  );
366 
367  buf[0] = '\0';
368 
369  if (ast_strlen_zero(parse)) {
370  ast_log(LOG_WARNING, "DB_DELETE requires an argument, DB_DELETE(<family>/<key>)\n");
371  return -1;
372  }
373 
374  AST_NONSTANDARD_APP_ARGS(args, parse, '/');
375 
376  if (args.argc < 2) {
377  ast_log(LOG_WARNING, "DB_DELETE requires an argument, DB_DELETE(<family>/<key>)\n");
378  return -1;
379  }
380 
381  if (ast_db_get(args.family, args.key, buf, len - 1)) {
382  ast_debug(1, "DB_DELETE: %s/%s not found in database.\n", args.family, args.key);
383  } else {
384  if (ast_db_del(args.family, args.key)) {
385  ast_debug(1, "DB_DELETE: %s/%s could not be deleted from the database\n", args.family, args.key);
386  }
387  }
388 
389  pbx_builtin_setvar_helper(chan, "DB_RESULT", buf);
390 
391  return 0;
392 }
393 
394 /*!
395  * \brief Wrapper to execute DB_DELETE from a write operation. Allows execution
396  * even if live_dangerously is disabled.
397  */
398 static int function_db_delete_write(struct ast_channel *chan, const char *cmd, char *parse,
399  const char *value)
400 {
401  /* Throwaway to hold the result from the read */
402  char buf[128];
403  return function_db_delete(chan, cmd, parse, buf, sizeof(buf));
404 }
405 
406 static struct ast_custom_function db_delete_function = {
407  .name = "DB_DELETE",
408  .read = function_db_delete,
409  .write = function_db_delete_write,
410 };
411 
412 static int unload_module(void)
413 {
414  int res = 0;
415 
416  res |= ast_custom_function_unregister(&db_function);
417  res |= ast_custom_function_unregister(&db_exists_function);
418  res |= ast_custom_function_unregister(&db_delete_function);
419  res |= ast_custom_function_unregister(&db_keys_function);
420  res |= ast_custom_function_unregister(&db_keycount_function);
421 
422  return res;
423 }
424 
425 static int load_module(void)
426 {
427  int res = 0;
428 
429  res |= ast_custom_function_register_escalating(&db_function, AST_CFE_BOTH);
430  res |= ast_custom_function_register(&db_exists_function);
431  res |= ast_custom_function_register_escalating(&db_delete_function, AST_CFE_READ);
432  res |= ast_custom_function_register(&db_keys_function);
433  res |= ast_custom_function_register(&db_keycount_function);
434 
435  return res;
436 }
437 
438 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Database (astdb) related dialplan functions");
const char * name
Definition: pbx.h:119
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
void ast_db_freetree(struct ast_db_entry *entry)
Free structure created by ast_db_gettree()
Definition: main/db.c:677
char * ast_str_append_escapecommas(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Append a non-NULL terminated substring to the end of a dynamic string, with escaping of commas...
Definition: strings.h:1076
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
Utility functions.
#define ast_custom_function_register_escalating(acf, escalation)
Register a custom function which requires escalated privileges.
Definition: pbx.h:1567
General Asterisk PBX channel definitions.
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
static int function_db_delete_write(struct ast_channel *chan, const char *cmd, char *parse, const char *value)
Wrapper to execute DB_DELETE from a write operation. Allows execution even if live_dangerously is dis...
Definition: func_db.c:398
#define ast_debug(level,...)
Log a DEBUG message.
Core PBX routines and definitions.
Support for dynamic strings.
Definition: strings.h:623
struct ast_db_entry * ast_db_gettree(const char *family, const char *keytree)
Get a list of values within the astdb tree.
Definition: main/db.c:610
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
Definition: astdb.h:31
int ast_db_get(const char *family, const char *key, char *value, int valuelen)
Get key value specified by family/key.
Definition: main/db.c:427
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:693
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: main/db.c:476
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: main/db.c:342
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
Persistent data storage (akin to *doze registry)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
#define AST_APP_ARG(name)
Define an application argument.