Merged revisions 87262 via svnmerge from
[asterisk/asterisk.git] / funcs / func_realtime.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2005-2006, BJ Weschke. All rights reserved.
5  * 
6  * BJ Weschke <bweschke@btwtech.com>
7  * 
8  * This code is released by the author with no restrictions on usage. 
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  */
17
18 /*! \file
19  *
20  * \brief REALTIME dialplan function
21  * 
22  * \author BJ Weschke <bweschke@btwtech.com>
23  * 
24  * \ingroup functions
25  */
26
27 #include "asterisk.h"
28
29 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <sys/types.h>
36
37 #include "asterisk/file.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/pbx.h"
40 #include "asterisk/options.h"
41 #include "asterisk/config.h"
42 #include "asterisk/module.h"
43 #include "asterisk/lock.h"
44 #include "asterisk/logger.h"
45 #include "asterisk/utils.h"
46 #include "asterisk/app.h"
47
48 static int function_realtime_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) 
49 {
50         struct ast_variable *var, *head;
51         struct ast_str *out;
52         size_t resultslen;
53         int n;
54         AST_DECLARE_APP_ARGS(args,
55                 AST_APP_ARG(family);
56                 AST_APP_ARG(fieldmatch);
57                 AST_APP_ARG(value);
58                 AST_APP_ARG(delim1);
59                 AST_APP_ARG(delim2);
60         );
61
62         if (ast_strlen_zero(data)) {
63                 ast_log(LOG_WARNING, "Syntax: REALTIME(family,fieldmatch[,value[,delim1[,delim2]]]) - missing argument!\n");
64                 return -1;
65         }
66
67         AST_STANDARD_APP_ARGS(args, data);
68
69         if (!args.delim1)
70                 args.delim1 = ",";
71         if (!args.delim2)
72                 args.delim2 = "=";
73
74         if (chan)
75                 ast_autoservice_start(chan);
76
77         head = ast_load_realtime_all(args.family, args.fieldmatch, args.value, NULL);
78
79         if (!head)
80                 if (chan)
81                         ast_autoservice_stop(chan);
82                 return -1;
83
84         resultslen = 0;
85         n = 0;
86         for (var = head; var; n++, var = var->next)
87                 resultslen += strlen(var->name) + strlen(var->value);
88         /* add space for delimiters and final '\0' */
89         resultslen += n * (strlen(args.delim1) + strlen(args.delim2)) + 1;
90
91         out = ast_str_alloca(resultslen);
92         for (var = head; var; var = var->next)
93                 ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
94         ast_copy_string(buf, out->str, len);
95
96         if (chan)
97                 ast_autoservice_stop(chan);
98
99         return 0;
100 }
101
102 static int function_realtime_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
103 {
104         int res = 0;
105         AST_DECLARE_APP_ARGS(args,
106                 AST_APP_ARG(family);
107                 AST_APP_ARG(fieldmatch);
108                 AST_APP_ARG(value);
109                 AST_APP_ARG(field);
110         );
111
112         if (ast_strlen_zero(data)) {
113                 ast_log(LOG_WARNING, "Syntax: REALTIME(family,fieldmatch,value,newcol) - missing argument!\n");
114                 return -1;
115         }
116
117         if (chan)
118                 ast_autoservice_start(chan);
119
120         AST_STANDARD_APP_ARGS(args, data);
121
122         res = ast_update_realtime(args.family, args.fieldmatch, args.value, args.field, (char *)value, NULL);
123
124         if (res < 0) {
125                 ast_log(LOG_WARNING, "Failed to update. Check the debug log for possible data repository related entries.\n");
126         }
127
128         if (chan)
129                 ast_autoservice_stop(chan);
130
131         return 0;
132 }
133
134 struct ast_custom_function realtime_function = {
135         .name = "REALTIME",
136         .synopsis = "RealTime Read/Write Functions",
137         .syntax = "REALTIME(family,fieldmatch[,value[,delim1[,delim2]]]) on read\n"
138                   "REALTIME(family,fieldmatch,value,field) on write",
139         .desc = "This function will read or write values from/to a RealTime repository.\n"
140                 "REALTIME(....) will read names/values from the repository, and \n"
141                 "REALTIME(....)= will write a new value/field to the repository. On a\n"
142                 "read, this function returns a delimited text string. The name/value \n"
143                 "pairs are delimited by delim1, and the name and value are delimited \n"
144                 "between each other with delim2. The default for delim1 is ',' and   \n"
145                 "the default for delim2 is '='. If there is no match, NULL will be   \n"
146                 "returned by the function. On a write, this function will always     \n"
147                 "return NULL. \n",
148         .read = function_realtime_read,
149         .write = function_realtime_write,
150 };
151
152 static int unload_module(void)
153 {
154         return ast_custom_function_unregister(&realtime_function);
155 }
156
157 static int load_module(void)
158 {
159         return ast_custom_function_register(&realtime_function);
160 }
161
162 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Read/Write values from a RealTime repository");