First pass at properly handling account codes in forwarding
[asterisk/asterisk.git] / db.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Channel Management
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 /* DB3 is licensed under Sleepycat Public License and is thus incompatible
15    with GPL.  To avoid having to make another exception (and complicate 
16    licensing even further) we elect to use DB1 which is BSD licensed */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/time.h>
22 #include <signal.h>
23 #include <errno.h>
24 #include <unistd.h>
25 #include <dirent.h>
26 #include <asterisk/channel.h>
27 #include <asterisk/file.h>
28 #include <asterisk/app.h>
29 #include <asterisk/dsp.h>
30 #include <asterisk/logger.h>
31 #include <asterisk/options.h>
32 #include <asterisk/astdb.h>
33 #include <asterisk/cli.h>
34 #include <asterisk/utils.h>
35 #include <asterisk/lock.h>
36 #include "db1-ast/include/db.h"
37 #include "asterisk.h"
38 #include "astconf.h"
39
40 static DB *astdb;
41 AST_MUTEX_DEFINE_STATIC(dblock);
42
43 static int dbinit(void) 
44 {
45         if (!astdb) {
46                 if (!(astdb = dbopen((char *)ast_config_AST_DB, O_CREAT | O_RDWR, 0664, DB_BTREE, NULL))) {
47                         ast_log(LOG_WARNING, "Unable to open Asterisk database\n");
48                 }
49         }
50         if (astdb)
51                 return 0;
52         return -1;
53 }
54
55
56 static inline int keymatch(const char *key, const char *prefix)
57 {
58         int preflen = strlen(prefix);
59         if (!preflen)
60                 return 1;
61         if (!strcasecmp(key, prefix))
62                 return 1;
63         if ((strlen(key) > preflen) &&
64                 !strncasecmp(key, prefix, preflen)) {
65                 if (key[preflen] == '/')
66                         return 1;
67         }
68         return 0;
69 }
70
71 int ast_db_deltree(const char *family, const char *keytree)
72 {
73         char prefix[256];
74         DBT key, data;
75         char *keys;
76         int res;
77         int pass;
78         
79         if (family) {
80                 if (keytree)
81                         snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
82                 else
83                         snprintf(prefix, sizeof(prefix), "/%s", family);
84         } else if (keytree)
85                 return -1;
86         else
87                 prefix[0] = '\0';
88         
89         ast_mutex_lock(&dblock);
90         if (dbinit()) 
91                 return -1;
92         
93         memset(&key, 0, sizeof(key));
94         memset(&data, 0, sizeof(data));
95         pass = 0;
96         while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
97                 if (key.size) {
98                         keys = key.data;
99                         keys[key.size - 1] = '\0';
100                 } else
101                         keys = "<bad key>";
102                 if (keymatch(keys, prefix)) {
103                         astdb->del(astdb, &key, 0);
104                 }
105         }
106         astdb->sync(astdb, 0);
107         ast_mutex_unlock(&dblock);
108         return 0;
109 }
110
111 int ast_db_put(const char *family, const char *keys, char *value)
112 {
113         char fullkey[256];
114         DBT key, data;
115         int res, fullkeylen;
116
117         ast_mutex_lock(&dblock);
118         if (dbinit()) {
119                 ast_mutex_unlock(&dblock);
120                 return -1;
121         }
122
123         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
124         memset(&key, 0, sizeof(key));
125         memset(&data, 0, sizeof(data));
126         key.data = fullkey;
127         key.size = fullkeylen + 1;
128         data.data = value;
129         data.size = strlen(value) + 1;
130         res = astdb->put(astdb, &key, &data, 0);
131         astdb->sync(astdb, 0);
132         ast_mutex_unlock(&dblock);
133         if (res)
134                 ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family);
135         return res;
136 }
137
138 int ast_db_get(const char *family, const char *keys, char *value, int valuelen)
139 {
140         char fullkey[256]="";
141         DBT key, data;
142         int res, fullkeylen;
143
144         ast_mutex_lock(&dblock);
145         if (dbinit()) {
146                 ast_mutex_unlock(&dblock);
147                 return -1;
148         }
149
150         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
151         memset(&key, 0, sizeof(key));
152         memset(&data, 0, sizeof(data));
153         memset(value, 0, valuelen);
154         key.data = fullkey;
155         key.size = fullkeylen + 1;
156         
157         res = astdb->get(astdb, &key, &data, 0);
158         
159         ast_mutex_unlock(&dblock);
160
161         /* Be sure to NULL terminate our data either way */
162         if (res) {
163                 ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
164         } else {
165 #if 0
166                 printf("Got value of size %d\n", data.size);
167 #endif
168                 if (data.size) {
169                         ((char *)data.data)[data.size - 1] = '\0';
170                         /* Make sure that we don't write too much to the dst pointer or we don't read too much from the source pointer */
171                         strncpy(value, data.data, (valuelen > data.size) ? data.size : valuelen);
172                         value[valuelen - 1] = '\0';
173                 } else {
174                         ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
175                 }
176         }
177         return res;
178 }
179
180 int ast_db_del(const char *family, const char *keys)
181 {
182         char fullkey[256];
183         DBT key;
184         int res, fullkeylen;
185
186         ast_mutex_lock(&dblock);
187         if (dbinit()) {
188                 ast_mutex_unlock(&dblock);
189                 return -1;
190         }
191         
192         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
193         memset(&key, 0, sizeof(key));
194         key.data = fullkey;
195         key.size = fullkeylen + 1;
196         
197         res = astdb->del(astdb, &key, 0);
198         astdb->sync(astdb, 0);
199         
200         ast_mutex_unlock(&dblock);
201
202         if (res) 
203                 ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
204         return res;
205 }
206
207 static int database_put(int fd, int argc, char *argv[])
208 {
209         int res;
210         if (argc != 5)
211                 return RESULT_SHOWUSAGE;
212         res = ast_db_put(argv[2], argv[3], argv[4]);
213         if (res) 
214                 ast_cli(fd, "Failed to update entry\n");
215         else
216                 ast_cli(fd, "Updated database successfully\n");
217         return RESULT_SUCCESS;
218 }
219
220 static int database_get(int fd, int argc, char *argv[])
221 {
222         int res;
223         char tmp[256];
224         if (argc != 4)
225                 return RESULT_SHOWUSAGE;
226         res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
227         if (res) 
228                 ast_cli(fd, "Database entry not found.\n");
229         else
230                 ast_cli(fd, "Value: %s\n", tmp);
231         return RESULT_SUCCESS;
232 }
233
234 static int database_del(int fd, int argc, char *argv[])
235 {
236         int res;
237         if (argc != 4)
238                 return RESULT_SHOWUSAGE;
239         res = ast_db_del(argv[2], argv[3]);
240         if (res) 
241                 ast_cli(fd, "Database entry does not exist.\n");
242         else
243                 ast_cli(fd, "Database entry removed.\n");
244         return RESULT_SUCCESS;
245 }
246
247 static int database_deltree(int fd, int argc, char *argv[])
248 {
249         int res;
250         if ((argc < 3) || (argc > 4))
251                 return RESULT_SHOWUSAGE;
252         if (argc == 4)
253                 res = ast_db_deltree(argv[2], argv[3]);
254         else
255                 res = ast_db_deltree(argv[2], NULL);
256         if (res) 
257                 ast_cli(fd, "Database entries do not exist.\n");
258         else
259                 ast_cli(fd, "Database entries removed.\n");
260         return RESULT_SUCCESS;
261 }
262
263 static int database_show(int fd, int argc, char *argv[])
264 {
265         char prefix[256];
266         DBT key, data;
267         char *keys, *values;
268         int res;
269         int pass;
270
271         if (argc == 4) {
272                 /* Family and key tree */
273                 snprintf(prefix, sizeof(prefix), "/%s/%s", argv[2], argv[3]);
274         } else if (argc == 3) {
275                 /* Family only */
276                 snprintf(prefix, sizeof(prefix), "/%s", argv[2]);
277         } else if (argc == 2) {
278                 /* Neither */
279                 prefix[0] = '\0';
280         } else
281                 return RESULT_SHOWUSAGE;
282         ast_mutex_lock(&dblock);
283         if (dbinit()) {
284                 ast_mutex_unlock(&dblock);
285                 ast_cli(fd, "Database unavailable\n");
286                 return RESULT_SUCCESS;  
287         }
288         memset(&key, 0, sizeof(key));
289         memset(&data, 0, sizeof(data));
290         pass = 0;
291         while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
292                 if (key.size) {
293                         keys = key.data;
294                         keys[key.size - 1] = '\0';
295                 } else
296                         keys = "<bad key>";
297                 if (data.size) {
298                         values = data.data;
299                         values[data.size - 1]='\0';
300                 } else
301                         values = "<bad value>";
302                 if (keymatch(keys, prefix)) {
303                                 ast_cli(fd, "%-50s: %-25s\n", keys, values);
304                 }
305         }
306         ast_mutex_unlock(&dblock);
307         return RESULT_SUCCESS;  
308 }
309
310 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
311 {
312         char prefix[256];
313         DBT key, data;
314         char *keys, *values;
315         int res;
316         int pass;
317         struct ast_db_entry *last = NULL;
318         struct ast_db_entry *cur, *ret=NULL;
319
320         if (family && !ast_strlen_zero(family)) {
321                 if (keytree && !ast_strlen_zero(keytree))
322                         /* Family and key tree */
323                         snprintf(prefix, sizeof(prefix), "/%s/%s", family, prefix);
324                 else
325                         /* Family only */
326                         snprintf(prefix, sizeof(prefix), "/%s", family);
327         } else
328                 prefix[0] = '\0';
329         ast_mutex_lock(&dblock);
330         if (dbinit()) {
331                 ast_mutex_unlock(&dblock);
332                 ast_log(LOG_WARNING, "Database unavailable\n");
333                 return NULL;    
334         }
335         memset(&key, 0, sizeof(key));
336         memset(&data, 0, sizeof(data));
337         pass = 0;
338         while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
339                 if (key.size) {
340                         keys = key.data;
341                         keys[key.size - 1] = '\0';
342                 } else
343                         keys = "<bad key>";
344                 if (data.size) {
345                         values = data.data;
346                         values[data.size - 1]='\0';
347                 } else
348                         values = "<bad value>";
349                 if (keymatch(keys, prefix)) {
350                                 cur = malloc(sizeof(struct ast_db_entry) + strlen(keys) + strlen(values) + 2);
351                                 if (cur) {
352                                         cur->next = NULL;
353                                         cur->key = cur->data + strlen(values) + 1;
354                                         strcpy(cur->data, values);
355                                         strcpy(cur->key, keys);
356                                         if (last)
357                                                 last->next = cur;
358                                         else
359                                                 ret = cur;
360                                         last = cur;
361                                 }
362                 }
363         }
364         ast_mutex_unlock(&dblock);
365         return ret;     
366 }
367
368 void ast_db_freetree(struct ast_db_entry *dbe)
369 {
370         struct ast_db_entry *last;
371         while(dbe) {
372                 last = dbe;
373                 dbe = dbe->next;
374                 free(last);
375         }
376 }
377
378 static char database_show_usage[] =
379 "Usage: database show [family [keytree]]\n"
380 "       Shows Asterisk database contents, optionally restricted\n"
381 "to a given family, or family and keytree.\n";
382
383 static char database_put_usage[] =
384 "Usage: database put <family> <key> <value>\n"
385 "       Adds or updates an entry in the Asterisk database for\n"
386 "a given family, key, and value.\n";
387
388 static char database_get_usage[] =
389 "Usage: database get <family> <key>\n"
390 "       Retrieves an entry in the Asterisk database for a given\n"
391 "family and key.\n";
392
393 static char database_del_usage[] =
394 "Usage: database del <family> <key>\n"
395 "       Deletes an entry in the Asterisk database for a given\n"
396 "family and key.\n";
397
398 static char database_deltree_usage[] =
399 "Usage: database deltree <family> [keytree]\n"
400 "       Deletes a family or specific keytree within a family\n"
401 "in the Asterisk database.\n";
402
403 struct ast_cli_entry cli_database_show =
404 { { "database", "show", NULL }, database_show, "Shows database contents", database_show_usage };
405
406 struct ast_cli_entry cli_database_get =
407 { { "database", "get", NULL }, database_get, "Gets database value", database_get_usage };
408
409 struct ast_cli_entry cli_database_put =
410 { { "database", "put", NULL }, database_put, "Adds/updates database value", database_put_usage };
411
412 struct ast_cli_entry cli_database_del =
413 { { "database", "del", NULL }, database_del, "Removes database key/value", database_del_usage };
414
415 struct ast_cli_entry cli_database_deltree =
416 { { "database", "deltree", NULL }, database_deltree, "Removes database keytree/values", database_deltree_usage };
417
418 int astdb_init(void)
419 {
420         dbinit();
421         ast_cli_register(&cli_database_show);
422         ast_cli_register(&cli_database_get);
423         ast_cli_register(&cli_database_put);
424         ast_cli_register(&cli_database_del);
425         ast_cli_register(&cli_database_deltree);
426         return 0;
427 }