Automatically create new buddy upon reception of a presence stanza of
[asterisk/asterisk.git] / funcs / func_devstate.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2007, Digium, Inc.
5  *
6  * Russell Bryant <russell@digium.com> 
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Manually controlled blinky lights
22  *
23  * \author Russell Bryant <russell@digium.com> 
24  *
25  * \ingroup functions
26  *
27  * \note Props go out to Ahrimanes in \#asterisk for requesting this at 4:30 AM
28  *       when I couldn't sleep.  :)
29  */
30
31 #include "asterisk.h"
32
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34
35 #include "asterisk/module.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/pbx.h"
38 #include "asterisk/utils.h"
39 #include "asterisk/linkedlists.h"
40 #include "asterisk/devicestate.h"
41 #include "asterisk/cli.h"
42 #include "asterisk/astdb.h"
43 #include "asterisk/app.h"
44
45 static const char astdb_family[] = "CustomDevstate";
46
47 static int devstate_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
48 {
49         ast_copy_string(buf, ast_devstate_str(ast_device_state(data)), len);
50
51         return 0;
52 }
53
54 static int devstate_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
55 {
56         size_t len = strlen("Custom:");
57
58         if (strncasecmp(data, "Custom:", len)) {
59                 ast_log(LOG_WARNING, "The DEVICE_STATE function can only be used to set 'Custom:' device state!\n");
60                 return -1;
61         }
62         data += len;
63         if (ast_strlen_zero(data)) {
64                 ast_log(LOG_WARNING, "DEVICE_STATE function called with no custom device name!\n");
65                 return -1;
66         }
67
68         ast_db_put(astdb_family, data, value);
69
70         ast_devstate_changed(ast_devstate_val(value), "Custom:%s", data);
71
72         return 0;
73 }
74
75 enum {
76         HINT_OPT_NAME = (1 << 0),
77 };
78
79 AST_APP_OPTIONS(hint_options, BEGIN_OPTIONS
80         AST_APP_OPTION('n', HINT_OPT_NAME),
81 END_OPTIONS );
82
83 static int hint_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
84 {
85         char *exten, *context;
86         AST_DECLARE_APP_ARGS(args,
87                 AST_APP_ARG(exten);
88                 AST_APP_ARG(options);
89         );
90         struct ast_flags opts = { 0, };
91         int res;
92
93         if (ast_strlen_zero(data)) {
94                 ast_log(LOG_WARNING, "The HINT function requires an extension\n");
95                 return -1;
96         }
97
98         AST_STANDARD_APP_ARGS(args, data);
99
100         if (ast_strlen_zero(args.exten)) {
101                 ast_log(LOG_WARNING, "The HINT function requires an extension\n");
102                 return -1;
103         }
104
105         context = exten = args.exten;
106         strsep(&context, "@");
107         if (ast_strlen_zero(context))
108                 context = "default";
109
110         if (!ast_strlen_zero(args.options))
111                 ast_app_parse_options(hint_options, &opts, NULL, args.options);
112
113         if (ast_test_flag(&opts, HINT_OPT_NAME))
114                 res = ast_get_hint(NULL, 0, buf, len, chan, context, exten);
115         else
116                 res = ast_get_hint(buf, len, NULL, 0, chan, context, exten);
117
118         return !res; /* ast_get_hint returns non-zero on success */
119 }
120
121 static enum ast_device_state custom_devstate_callback(const char *data)
122 {
123         char buf[256] = "";
124
125         ast_db_get(astdb_family, data, buf, sizeof(buf));
126
127         return ast_devstate_val(buf);
128 }
129
130 static char *handle_cli_funcdevstate_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
131 {
132         struct ast_db_entry *db_entry, *db_tree;
133
134         switch (cmd) {
135         case CLI_INIT:
136                 e->command = "funcdevstate list";
137                 e->usage =
138                         "Usage: funcdevstate list\n"
139                         "       List all custom device states that have been set by using\n"
140                         "       the DEVICE_STATE dialplan function.\n";
141                 return NULL;
142         case CLI_GENERATE:
143                 return NULL;
144         }
145
146         if (a->argc != e->args)
147                 return CLI_SHOWUSAGE;
148
149         ast_cli(a->fd, "\n"
150                 "---------------------------------------------------------------------\n"
151                 "--- Custom Device States --------------------------------------------\n"
152                 "---------------------------------------------------------------------\n"
153                 "---\n");
154
155         db_entry = db_tree = ast_db_gettree(astdb_family, NULL);
156         for (; db_entry; db_entry = db_entry->next) {
157                 const char *dev_name = strrchr(db_entry->key, '/') + 1;
158                 if (dev_name <= (const char *) 1)
159                         continue;
160                 ast_cli(a->fd, "--- Name: 'Custom:%s'  State: '%s'\n"
161                                "---\n", dev_name, db_entry->data);
162         }
163         ast_db_freetree(db_tree);
164         db_tree = NULL;
165
166         ast_cli(a->fd,
167                 "---------------------------------------------------------------------\n"
168                 "---------------------------------------------------------------------\n"
169                 "\n");
170
171         return CLI_SUCCESS;
172 }
173
174 static char *handle_cli_devstate_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
175 {
176         struct ast_db_entry *db_entry, *db_tree;
177
178         switch (cmd) {
179         case CLI_INIT:
180                 e->command = "devstate list";
181                 e->usage =
182                         "Usage: devstate list\n"
183                         "       List all custom device states that have been set by using\n"
184                         "       the DEVICE_STATE dialplan function.\n";
185                 return NULL;
186         case CLI_GENERATE:
187                 return NULL;
188         }
189
190         if (a->argc != e->args)
191                 return CLI_SHOWUSAGE;
192
193         ast_cli(a->fd, "\n"
194                 "---------------------------------------------------------------------\n"
195                 "--- Custom Device States --------------------------------------------\n"
196                 "---------------------------------------------------------------------\n"
197                 "---\n");
198
199         db_entry = db_tree = ast_db_gettree(astdb_family, NULL);
200         for (; db_entry; db_entry = db_entry->next) {
201                 const char *dev_name = strrchr(db_entry->key, '/') + 1;
202                 if (dev_name <= (const char *) 1)
203                         continue;
204                 ast_cli(a->fd, "--- Name: 'Custom:%s'  State: '%s'\n"
205                                "---\n", dev_name, db_entry->data);
206         }
207         ast_db_freetree(db_tree);
208         db_tree = NULL;
209
210         ast_cli(a->fd,
211                 "---------------------------------------------------------------------\n"
212                 "---------------------------------------------------------------------\n"
213                 "\n");
214
215         return CLI_SUCCESS;
216 }
217
218 static struct ast_cli_entry cli_funcdevstate_list_deprecated = AST_CLI_DEFINE(handle_cli_funcdevstate_list, "List currently known custom device states");
219 static struct ast_cli_entry cli_funcdevstate[] = {
220         AST_CLI_DEFINE(handle_cli_devstate_list, "List currently known custom device states", .deprecate_cmd = &cli_funcdevstate_list_deprecated),
221 };
222
223 static struct ast_custom_function devstate_function = {
224         .name = "DEVICE_STATE",
225         .synopsis = "Get or Set a device state",
226         .syntax = "DEVICE_STATE(device)",
227         .desc =
228         "  The DEVICE_STATE function can be used to retrieve the device state from any\n"
229         "device state provider.  For example:\n"
230         "   NoOp(SIP/mypeer has state ${DEVICE_STATE(SIP/mypeer)})\n"
231         "   NoOp(Conference number 1234 has state ${DEVICE_STATE(MeetMe:1234)})\n"
232         "\n"
233         "  The DEVICE_STATE function can also be used to set custom device state from\n"
234         "the dialplan.  The \"Custom:\" prefix must be used.  For example:\n"
235         "  Set(DEVICE_STATE(Custom:lamp1)=BUSY)\n"
236         "  Set(DEVICE_STATE(Custom:lamp2)=NOT_INUSE)\n"
237         "You can subscribe to the status of a custom device state using a hint in\n"
238         "the dialplan:\n"
239         "  exten => 1234,hint,Custom:lamp1\n"
240         "\n"
241         "  The possible values for both uses of this function are:\n"
242         "UNKNOWN | NOT_INUSE | INUSE | BUSY | INVALID | UNAVAILABLE | RINGING\n"
243         "RINGINUSE | ONHOLD\n",
244         .read = devstate_read,
245         .write = devstate_write,
246 };
247
248 static struct ast_custom_function hint_function = {
249         .name = "HINT",
250         .synopsis = "Get the devices set for a dialplan hint",
251         .syntax = "HINT(extension[@context][|options])",
252         .desc =
253         "  The HINT function can be used to retrieve the list of devices that are\n"
254         "mapped to a dialplan hint.  For example:\n"
255         "   NoOp(Hint for Extension 1234 is ${HINT(1234)})\n"
256         "Options:\n"
257         "   'n' - Retrieve name on the hint instead of list of devices\n"
258         "",
259         .read = hint_read,
260 };
261
262 static int unload_module(void)
263 {
264         int res = 0;
265
266         res |= ast_custom_function_unregister(&devstate_function);
267         res |= ast_custom_function_unregister(&hint_function);
268         res |= ast_devstate_prov_del("Custom");
269         res |= ast_cli_unregister_multiple(cli_funcdevstate, ARRAY_LEN(cli_funcdevstate));
270
271         return res;
272 }
273
274 static int load_module(void)
275 {
276         int res = 0;
277         struct ast_db_entry *db_entry, *db_tree;
278
279         /* Populate the device state cache on the system with all of the currently
280          * known custom device states. */
281         db_entry = db_tree = ast_db_gettree(astdb_family, NULL);
282         for (; db_entry; db_entry = db_entry->next) {
283                 const char *dev_name = strrchr(db_entry->key, '/') + 1;
284                 if (dev_name <= (const char *) 1)
285                         continue;
286                 ast_devstate_changed(ast_devstate_val(db_entry->data),
287                         "Custom:%s\n", dev_name);
288         }
289         ast_db_freetree(db_tree);
290         db_tree = NULL;
291
292         res |= ast_custom_function_register(&devstate_function);
293         res |= ast_custom_function_register(&hint_function);
294         res |= ast_devstate_prov_add("Custom", custom_devstate_callback);
295         res |= ast_cli_register_multiple(cli_funcdevstate, ARRAY_LEN(cli_funcdevstate));
296
297         return res;
298 }
299
300 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Gets or sets a device state in the dialplan");