00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 374426 $")
00037
00038 #include "asterisk/_private.h"
00039 #include "asterisk/paths.h"
00040 #include <sys/time.h>
00041 #include <signal.h>
00042 #include <dirent.h>
00043
00044 #include "asterisk/channel.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/app.h"
00047 #include "asterisk/dsp.h"
00048 #include "asterisk/astdb.h"
00049 #include "asterisk/cli.h"
00050 #include "asterisk/utils.h"
00051 #include "asterisk/lock.h"
00052 #include "asterisk/manager.h"
00053 #include "db1-ast/include/db.h"
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107 #define MAX_DB_FIELD 256
00108
00109 static DB *astdb;
00110 AST_MUTEX_DEFINE_STATIC(dblock);
00111 static ast_cond_t dbcond;
00112 typedef int (*process_keys_cb)(DBT *key, DBT *value, const char *filter, void *data);
00113
00114 static void db_sync(void);
00115
00116 static int dbinit(void)
00117 {
00118 if (!astdb && !(astdb = dbopen(ast_config_AST_DB, O_CREAT | O_RDWR, AST_FILE_MODE, DB_BTREE, NULL))) {
00119 ast_log(LOG_WARNING, "Unable to open Asterisk database '%s': %s\n", ast_config_AST_DB, strerror(errno));
00120 return -1;
00121 }
00122 return 0;
00123 }
00124
00125
00126 static inline int keymatch(const char *key, const char *prefix)
00127 {
00128 int preflen = strlen(prefix);
00129 if (!preflen)
00130 return 1;
00131 if (!strcasecmp(key, prefix))
00132 return 1;
00133 if ((strlen(key) > preflen) && !strncasecmp(key, prefix, preflen)) {
00134 if (key[preflen] == '/')
00135 return 1;
00136 }
00137 return 0;
00138 }
00139
00140 static inline int subkeymatch(const char *key, const char *suffix)
00141 {
00142 int suffixlen = strlen(suffix);
00143 if (suffixlen) {
00144 const char *subkey = key + strlen(key) - suffixlen;
00145 if (subkey < key)
00146 return 0;
00147 if (!strcasecmp(subkey, suffix))
00148 return 1;
00149 }
00150 return 0;
00151 }
00152
00153 static const char *dbt_data2str(DBT *dbt)
00154 {
00155 char *data = "";
00156
00157 if (dbt->size) {
00158 data = dbt->data;
00159 data[dbt->size - 1] = '\0';
00160 }
00161
00162 return data;
00163 }
00164
00165 static inline const char *dbt_data2str_full(DBT *dbt, const char *def)
00166 {
00167 return S_OR(dbt_data2str(dbt), def);
00168 }
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 static int process_db_keys(process_keys_cb cb, void *data, const char *filter, int sync)
00181 {
00182 DBT key = { 0, }, value = { 0, }, last_key = { 0, };
00183 int counter = 0;
00184 int res, last = 0;
00185 char last_key_s[MAX_DB_FIELD];
00186
00187 ast_mutex_lock(&dblock);
00188 if (dbinit()) {
00189 ast_mutex_unlock(&dblock);
00190 return -1;
00191 }
00192
00193
00194
00195
00196
00197
00198 if (astdb->seq(astdb, &last_key, &value, R_LAST)) {
00199
00200 ast_mutex_unlock(&dblock);
00201 return 0;
00202 }
00203
00204 memcpy(last_key_s, last_key.data, MIN(last_key.size - 1, sizeof(last_key_s)));
00205 last_key_s[last_key.size - 1] = '\0';
00206 for (res = astdb->seq(astdb, &key, &value, R_FIRST);
00207 !res;
00208 res = astdb->seq(astdb, &key, &value, R_NEXT)) {
00209
00210 last = !strcmp(dbt_data2str_full(&key, "<bad key>"), last_key_s);
00211 counter += cb(&key, &value, filter, data);
00212 if (last) {
00213 break;
00214 }
00215 }
00216
00217 if (sync) {
00218 db_sync();
00219 }
00220
00221 ast_mutex_unlock(&dblock);
00222
00223 return counter;
00224 }
00225
00226 static int db_deltree_cb(DBT *key, DBT *value, const char *filter, void *data)
00227 {
00228 int res = 0;
00229
00230 if (keymatch(dbt_data2str_full(key, "<bad key>"), filter)) {
00231 astdb->del(astdb, key, 0);
00232 res = 1;
00233 }
00234 return res;
00235 }
00236
00237 int ast_db_deltree(const char *family, const char *keytree)
00238 {
00239 char prefix[MAX_DB_FIELD];
00240
00241 if (family) {
00242 if (keytree) {
00243 snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00244 } else {
00245 snprintf(prefix, sizeof(prefix), "/%s", family);
00246 }
00247 } else if (keytree) {
00248 return -1;
00249 } else {
00250 prefix[0] = '\0';
00251 }
00252
00253 return process_db_keys(db_deltree_cb, NULL, prefix, 1);
00254 }
00255
00256 int ast_db_put(const char *family, const char *keys, const char *value)
00257 {
00258 char fullkey[MAX_DB_FIELD];
00259 DBT key, data;
00260 int res, fullkeylen;
00261
00262 ast_mutex_lock(&dblock);
00263 if (dbinit()) {
00264 ast_mutex_unlock(&dblock);
00265 return -1;
00266 }
00267
00268 fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00269 memset(&key, 0, sizeof(key));
00270 memset(&data, 0, sizeof(data));
00271 key.data = fullkey;
00272 key.size = fullkeylen + 1;
00273 data.data = (char *) value;
00274 data.size = strlen(value) + 1;
00275 res = astdb->put(astdb, &key, &data, 0);
00276 db_sync();
00277 ast_mutex_unlock(&dblock);
00278 if (res)
00279 ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family);
00280
00281 return res;
00282 }
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298 static int db_get_common(const char *family, const char *keys, char **buffer, int bufferlen)
00299 {
00300 char fullkey[MAX_DB_FIELD] = "";
00301 DBT key, data;
00302 int res, fullkeylen;
00303
00304 ast_mutex_lock(&dblock);
00305 if (dbinit()) {
00306 ast_mutex_unlock(&dblock);
00307 return -1;
00308 }
00309
00310 fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00311 memset(&key, 0, sizeof(key));
00312 memset(&data, 0, sizeof(data));
00313 key.data = fullkey;
00314 key.size = fullkeylen + 1;
00315
00316 res = astdb->get(astdb, &key, &data, 0);
00317
00318
00319 if (res) {
00320 ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys, family);
00321 } else {
00322 if (data.size) {
00323 ((char *)data.data)[data.size - 1] = '\0';
00324
00325 if (bufferlen == -1) {
00326 *buffer = ast_strdup(data.data);
00327 } else {
00328
00329
00330 ast_copy_string(*buffer, data.data, bufferlen > data.size ? data.size : bufferlen);
00331 }
00332 } else {
00333 ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
00334 }
00335 }
00336
00337
00338
00339 ast_mutex_unlock(&dblock);
00340
00341 return res;
00342 }
00343
00344 int ast_db_get(const char *family, const char *keys, char *value, int valuelen)
00345 {
00346 ast_assert(value != NULL);
00347
00348
00349 value[0] = 0;
00350
00351 return db_get_common(family, keys, &value, valuelen);
00352 }
00353
00354 int ast_db_get_allocated(const char *family, const char *keys, char **out)
00355 {
00356 *out = NULL;
00357
00358 return db_get_common(family, keys, out, -1);
00359 }
00360
00361 int ast_db_del(const char *family, const char *keys)
00362 {
00363 char fullkey[MAX_DB_FIELD];
00364 DBT key;
00365 int res, fullkeylen;
00366
00367 ast_mutex_lock(&dblock);
00368 if (dbinit()) {
00369 ast_mutex_unlock(&dblock);
00370 return -1;
00371 }
00372
00373 fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00374 memset(&key, 0, sizeof(key));
00375 key.data = fullkey;
00376 key.size = fullkeylen + 1;
00377
00378 res = astdb->del(astdb, &key, 0);
00379 db_sync();
00380
00381 ast_mutex_unlock(&dblock);
00382
00383 if (res) {
00384 ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys, family);
00385 }
00386 return res;
00387 }
00388
00389 static char *handle_cli_database_put(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00390 {
00391 int res;
00392
00393 switch (cmd) {
00394 case CLI_INIT:
00395 e->command = "database put";
00396 e->usage =
00397 "Usage: database put <family> <key> <value>\n"
00398 " Adds or updates an entry in the Asterisk database for\n"
00399 " a given family, key, and value.\n";
00400 return NULL;
00401 case CLI_GENERATE:
00402 return NULL;
00403 }
00404
00405 if (a->argc != 5)
00406 return CLI_SHOWUSAGE;
00407 res = ast_db_put(a->argv[2], a->argv[3], a->argv[4]);
00408 if (res) {
00409 ast_cli(a->fd, "Failed to update entry\n");
00410 } else {
00411 ast_cli(a->fd, "Updated database successfully\n");
00412 }
00413 return CLI_SUCCESS;
00414 }
00415
00416 static char *handle_cli_database_get(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00417 {
00418 int res;
00419 char tmp[MAX_DB_FIELD];
00420
00421 switch (cmd) {
00422 case CLI_INIT:
00423 e->command = "database get";
00424 e->usage =
00425 "Usage: database get <family> <key>\n"
00426 " Retrieves an entry in the Asterisk database for a given\n"
00427 " family and key.\n";
00428 return NULL;
00429 case CLI_GENERATE:
00430 return NULL;
00431 }
00432
00433 if (a->argc != 4)
00434 return CLI_SHOWUSAGE;
00435 res = ast_db_get(a->argv[2], a->argv[3], tmp, sizeof(tmp));
00436 if (res) {
00437 ast_cli(a->fd, "Database entry not found.\n");
00438 } else {
00439 ast_cli(a->fd, "Value: %s\n", tmp);
00440 }
00441 return CLI_SUCCESS;
00442 }
00443
00444 static char *handle_cli_database_del(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00445 {
00446 int res;
00447
00448 switch (cmd) {
00449 case CLI_INIT:
00450 e->command = "database del";
00451 e->usage =
00452 "Usage: database del <family> <key>\n"
00453 " Deletes an entry in the Asterisk database for a given\n"
00454 " family and key.\n";
00455 return NULL;
00456 case CLI_GENERATE:
00457 return NULL;
00458 }
00459
00460 if (a->argc != 4)
00461 return CLI_SHOWUSAGE;
00462 res = ast_db_del(a->argv[2], a->argv[3]);
00463 if (res) {
00464 ast_cli(a->fd, "Database entry does not exist.\n");
00465 } else {
00466 ast_cli(a->fd, "Database entry removed.\n");
00467 }
00468 return CLI_SUCCESS;
00469 }
00470
00471 static char *handle_cli_database_deltree(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00472 {
00473 int num_deleted;
00474
00475 switch (cmd) {
00476 case CLI_INIT:
00477 e->command = "database deltree";
00478 e->usage =
00479 "Usage: database deltree <family> [keytree]\n"
00480 " OR: database deltree <family>[/keytree]\n"
00481 " Deletes a family or specific keytree within a family\n"
00482 " in the Asterisk database. The two arguments may be\n"
00483 " separated by either a space or a slash.\n";
00484 return NULL;
00485 case CLI_GENERATE:
00486 return NULL;
00487 }
00488
00489 if ((a->argc < 3) || (a->argc > 4))
00490 return CLI_SHOWUSAGE;
00491 if (a->argc == 4) {
00492 num_deleted = ast_db_deltree(a->argv[2], a->argv[3]);
00493 } else {
00494 num_deleted = ast_db_deltree(a->argv[2], NULL);
00495 }
00496 if (num_deleted < 0) {
00497 ast_cli(a->fd, "Database unavailable.\n");
00498 } else if (num_deleted == 0) {
00499 ast_cli(a->fd, "Database entries do not exist.\n");
00500 } else {
00501 ast_cli(a->fd, "%d database entries removed.\n",num_deleted);
00502 }
00503 return CLI_SUCCESS;
00504 }
00505
00506 static int db_show_cb(DBT *key, DBT *value, const char *filter, void *data)
00507 {
00508 struct ast_cli_args *a = data;
00509 const char *key_s = dbt_data2str_full(key, "<bad key>");
00510 const char *value_s = dbt_data2str_full(value, "<bad value>");
00511
00512 if (keymatch(key_s, filter)) {
00513 ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
00514 return 1;
00515 }
00516
00517 return 0;
00518 }
00519
00520 static char *handle_cli_database_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00521 {
00522 char prefix[MAX_DB_FIELD];
00523 int counter = 0;
00524
00525 switch (cmd) {
00526 case CLI_INIT:
00527 e->command = "database show";
00528 e->usage =
00529 "Usage: database show [family [keytree]]\n"
00530 " OR: database show [family[/keytree]]\n"
00531 " Shows Asterisk database contents, optionally restricted\n"
00532 " to a given family, or family and keytree. The two arguments\n"
00533 " may be separated either by a space or by a slash.\n";
00534 return NULL;
00535 case CLI_GENERATE:
00536 return NULL;
00537 }
00538
00539 if (a->argc == 4) {
00540
00541 snprintf(prefix, sizeof(prefix), "/%s/%s", a->argv[2], a->argv[3]);
00542 } else if (a->argc == 3) {
00543
00544 snprintf(prefix, sizeof(prefix), "/%s", a->argv[2]);
00545 } else if (a->argc == 2) {
00546
00547 prefix[0] = '\0';
00548 } else {
00549 return CLI_SHOWUSAGE;
00550 }
00551
00552 if((counter = process_db_keys(db_show_cb, a, prefix, 0)) < 0) {
00553 ast_cli(a->fd, "Database unavailable\n");
00554 return CLI_SUCCESS;
00555 }
00556
00557 ast_cli(a->fd, "%d results found.\n", counter);
00558 return CLI_SUCCESS;
00559 }
00560
00561 static int db_showkey_cb(DBT *key, DBT *value, const char *filter, void *data)
00562 {
00563 struct ast_cli_args *a = data;
00564 const char *key_s = dbt_data2str_full(key, "<bad key>");
00565 const char *value_s = dbt_data2str_full(value, "<bad value>");
00566
00567 if (subkeymatch(key_s, filter)) {
00568 ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
00569 return 1;
00570 }
00571
00572 return 0;
00573 }
00574
00575 static char *handle_cli_database_showkey(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00576 {
00577 char suffix[MAX_DB_FIELD];
00578 int counter = 0;
00579
00580 switch (cmd) {
00581 case CLI_INIT:
00582 e->command = "database showkey";
00583 e->usage =
00584 "Usage: database showkey <keytree>\n"
00585 " Shows Asterisk database contents, restricted to a given key.\n";
00586 return NULL;
00587 case CLI_GENERATE:
00588 return NULL;
00589 }
00590
00591 if (a->argc == 3) {
00592
00593 snprintf(suffix, sizeof(suffix), "/%s", a->argv[2]);
00594 } else {
00595 return CLI_SHOWUSAGE;
00596 }
00597
00598 if ((counter = process_db_keys(db_showkey_cb, a, suffix, 0)) < 0) {
00599 ast_cli(a->fd, "Database unavailable\n");
00600 return CLI_SUCCESS;
00601 }
00602
00603 ast_cli(a->fd, "%d results found.\n", counter);
00604 return CLI_SUCCESS;
00605 }
00606
00607 static int db_gettree_cb(DBT *key, DBT *value, const char *filter, void *data)
00608 {
00609 struct ast_db_entry **ret = data;
00610 struct ast_db_entry *cur;
00611 const char *key_s = dbt_data2str_full(key, "<bad key>");
00612 const char *value_s = dbt_data2str_full(value, "<bad value>");
00613 size_t key_slen = strlen(key_s) + 1, value_slen = strlen(value_s) + 1;
00614
00615 if (keymatch(key_s, filter) && (cur = ast_malloc(sizeof(*cur) + key_slen + value_slen))) {
00616 cur->next = *ret;
00617 cur->key = cur->data + value_slen;
00618 strcpy(cur->data, value_s);
00619 strcpy(cur->key, key_s);
00620 *ret = cur;
00621 return 1;
00622 }
00623
00624 return 0;
00625 }
00626
00627 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
00628 {
00629 char prefix[MAX_DB_FIELD];
00630 struct ast_db_entry *ret = NULL;
00631
00632 if (!ast_strlen_zero(family)) {
00633 if (!ast_strlen_zero(keytree)) {
00634
00635 snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00636 } else {
00637
00638 snprintf(prefix, sizeof(prefix), "/%s", family);
00639 }
00640 } else {
00641 prefix[0] = '\0';
00642 }
00643
00644 if (process_db_keys(db_gettree_cb, &ret, prefix, 0) < 0) {
00645 ast_log(LOG_WARNING, "Database unavailable\n");
00646 return NULL;
00647 }
00648
00649 return ret;
00650 }
00651
00652 void ast_db_freetree(struct ast_db_entry *dbe)
00653 {
00654 struct ast_db_entry *last;
00655 while (dbe) {
00656 last = dbe;
00657 dbe = dbe->next;
00658 ast_free(last);
00659 }
00660 }
00661
00662 static struct ast_cli_entry cli_database[] = {
00663 AST_CLI_DEFINE(handle_cli_database_show, "Shows database contents"),
00664 AST_CLI_DEFINE(handle_cli_database_showkey, "Shows database contents"),
00665 AST_CLI_DEFINE(handle_cli_database_get, "Gets database value"),
00666 AST_CLI_DEFINE(handle_cli_database_put, "Adds/updates database value"),
00667 AST_CLI_DEFINE(handle_cli_database_del, "Removes database key/value"),
00668 AST_CLI_DEFINE(handle_cli_database_deltree, "Removes database keytree/values")
00669 };
00670
00671 static int manager_dbput(struct mansession *s, const struct message *m)
00672 {
00673 const char *family = astman_get_header(m, "Family");
00674 const char *key = astman_get_header(m, "Key");
00675 const char *val = astman_get_header(m, "Val");
00676 int res;
00677
00678 if (ast_strlen_zero(family)) {
00679 astman_send_error(s, m, "No family specified");
00680 return 0;
00681 }
00682 if (ast_strlen_zero(key)) {
00683 astman_send_error(s, m, "No key specified");
00684 return 0;
00685 }
00686
00687 res = ast_db_put(family, key, S_OR(val, ""));
00688 if (res) {
00689 astman_send_error(s, m, "Failed to update entry");
00690 } else {
00691 astman_send_ack(s, m, "Updated database successfully");
00692 }
00693 return 0;
00694 }
00695
00696 static int manager_dbget(struct mansession *s, const struct message *m)
00697 {
00698 const char *id = astman_get_header(m,"ActionID");
00699 char idText[256] = "";
00700 const char *family = astman_get_header(m, "Family");
00701 const char *key = astman_get_header(m, "Key");
00702 char tmp[MAX_DB_FIELD];
00703 int res;
00704
00705 if (ast_strlen_zero(family)) {
00706 astman_send_error(s, m, "No family specified.");
00707 return 0;
00708 }
00709 if (ast_strlen_zero(key)) {
00710 astman_send_error(s, m, "No key specified.");
00711 return 0;
00712 }
00713
00714 if (!ast_strlen_zero(id))
00715 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
00716
00717 res = ast_db_get(family, key, tmp, sizeof(tmp));
00718 if (res) {
00719 astman_send_error(s, m, "Database entry not found");
00720 } else {
00721 astman_send_ack(s, m, "Result will follow");
00722 astman_append(s, "Event: DBGetResponse\r\n"
00723 "Family: %s\r\n"
00724 "Key: %s\r\n"
00725 "Val: %s\r\n"
00726 "%s"
00727 "\r\n",
00728 family, key, tmp, idText);
00729 astman_append(s, "Event: DBGetComplete\r\n"
00730 "%s"
00731 "\r\n",
00732 idText);
00733 }
00734 return 0;
00735 }
00736
00737 static int manager_dbdel(struct mansession *s, const struct message *m)
00738 {
00739 const char *family = astman_get_header(m, "Family");
00740 const char *key = astman_get_header(m, "Key");
00741 int res;
00742
00743 if (ast_strlen_zero(family)) {
00744 astman_send_error(s, m, "No family specified.");
00745 return 0;
00746 }
00747
00748 if (ast_strlen_zero(key)) {
00749 astman_send_error(s, m, "No key specified.");
00750 return 0;
00751 }
00752
00753 res = ast_db_del(family, key);
00754 if (res)
00755 astman_send_error(s, m, "Database entry not found");
00756 else
00757 astman_send_ack(s, m, "Key deleted successfully");
00758
00759 return 0;
00760 }
00761
00762 static int manager_dbdeltree(struct mansession *s, const struct message *m)
00763 {
00764 const char *family = astman_get_header(m, "Family");
00765 const char *key = astman_get_header(m, "Key");
00766 int num_deleted;
00767
00768 if (ast_strlen_zero(family)) {
00769 astman_send_error(s, m, "No family specified.");
00770 return 0;
00771 }
00772
00773 if (!ast_strlen_zero(key)) {
00774 num_deleted = ast_db_deltree(family, key);
00775 } else {
00776 num_deleted = ast_db_deltree(family, NULL);
00777 }
00778
00779 if (num_deleted < 0) {
00780 astman_send_error(s, m, "Database unavailable");
00781 } else if (num_deleted == 0) {
00782 astman_send_error(s, m, "Database entry not found");
00783 } else {
00784 astman_send_ack(s, m, "Key tree deleted successfully");
00785 }
00786
00787 return 0;
00788 }
00789
00790
00791
00792
00793
00794
00795
00796 static void db_sync(void)
00797 {
00798 ast_cond_signal(&dbcond);
00799 }
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811 static void *db_sync_thread(void *data)
00812 {
00813 ast_mutex_lock(&dblock);
00814 for (;;) {
00815 ast_cond_wait(&dbcond, &dblock);
00816 ast_mutex_unlock(&dblock);
00817 sleep(1);
00818 ast_mutex_lock(&dblock);
00819 astdb->sync(astdb, 0);
00820 }
00821
00822 return NULL;
00823 }
00824
00825 int astdb_init(void)
00826 {
00827 pthread_t dont_care;
00828
00829 ast_cond_init(&dbcond, NULL);
00830 if (ast_pthread_create_background(&dont_care, NULL, db_sync_thread, NULL)) {
00831 return -1;
00832 }
00833
00834
00835 dbinit();
00836
00837 ast_cli_register_multiple(cli_database, ARRAY_LEN(cli_database));
00838 ast_manager_register_xml("DBGet", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_dbget);
00839 ast_manager_register_xml("DBPut", EVENT_FLAG_SYSTEM, manager_dbput);
00840 ast_manager_register_xml("DBDel", EVENT_FLAG_SYSTEM, manager_dbdel);
00841 ast_manager_register_xml("DBDelTree", EVENT_FLAG_SYSTEM, manager_dbdeltree);
00842 return 0;
00843 }