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 #include "asterisk.h"
00034
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 193335 $")
00036
00037 #include "asterisk/module.h"
00038 #include "asterisk/channel.h"
00039 #include "asterisk/pbx.h"
00040 #include "asterisk/utils.h"
00041 #include "asterisk/linkedlists.h"
00042 #include "asterisk/devicestate.h"
00043 #include "asterisk/cli.h"
00044 #include "asterisk/astdb.h"
00045 #include "asterisk/app.h"
00046
00047 static const char astdb_family[] = "CustomDevstate";
00048
00049 static int devstate_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00050 {
00051 ast_copy_string(buf, ast_devstate_str(ast_device_state(data)), len);
00052
00053 return 0;
00054 }
00055
00056 static int devstate_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00057 {
00058 size_t len = strlen("Custom:");
00059 enum ast_device_state state_val;
00060
00061 if (strncasecmp(data, "Custom:", len)) {
00062 ast_log(LOG_WARNING, "The DEVICE_STATE function can only be used to set 'Custom:' device state!\n");
00063 return -1;
00064 }
00065 data += len;
00066 if (ast_strlen_zero(data)) {
00067 ast_log(LOG_WARNING, "DEVICE_STATE function called with no custom device name!\n");
00068 return -1;
00069 }
00070
00071 state_val = ast_devstate_val(value);
00072
00073 if (state_val == AST_DEVICE_UNKNOWN) {
00074 ast_log(LOG_ERROR, "DEVICE_STATE function given invalid state value '%s'\n", value);
00075 return -1;
00076 }
00077
00078 ast_db_put(astdb_family, data, value);
00079
00080 ast_devstate_changed(state_val, "Custom:%s", data);
00081
00082 return 0;
00083 }
00084
00085 enum {
00086 HINT_OPT_NAME = (1 << 0),
00087 };
00088
00089 AST_APP_OPTIONS(hint_options, BEGIN_OPTIONS
00090 AST_APP_OPTION('n', HINT_OPT_NAME),
00091 END_OPTIONS );
00092
00093 static int hint_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00094 {
00095 char *exten, *context;
00096 AST_DECLARE_APP_ARGS(args,
00097 AST_APP_ARG(exten);
00098 AST_APP_ARG(options);
00099 );
00100 struct ast_flags opts = { 0, };
00101 int res;
00102
00103 if (ast_strlen_zero(data)) {
00104 ast_log(LOG_WARNING, "The HINT function requires an extension\n");
00105 return -1;
00106 }
00107
00108 AST_STANDARD_APP_ARGS(args, data);
00109
00110 if (ast_strlen_zero(args.exten)) {
00111 ast_log(LOG_WARNING, "The HINT function requires an extension\n");
00112 return -1;
00113 }
00114
00115 context = exten = args.exten;
00116 strsep(&context, "@");
00117 if (ast_strlen_zero(context))
00118 context = "default";
00119
00120 if (!ast_strlen_zero(args.options))
00121 ast_app_parse_options(hint_options, &opts, NULL, args.options);
00122
00123 if (ast_test_flag(&opts, HINT_OPT_NAME))
00124 res = ast_get_hint(NULL, 0, buf, len, chan, context, exten);
00125 else
00126 res = ast_get_hint(buf, len, NULL, 0, chan, context, exten);
00127
00128 return !res;
00129 }
00130
00131 static enum ast_device_state custom_devstate_callback(const char *data)
00132 {
00133 char buf[256] = "";
00134
00135 ast_db_get(astdb_family, data, buf, sizeof(buf));
00136
00137 return ast_devstate_val(buf);
00138 }
00139
00140 static char *handle_cli_funcdevstate_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00141 {
00142 struct ast_db_entry *db_entry, *db_tree;
00143
00144 switch (cmd) {
00145 case CLI_INIT:
00146 e->command = "funcdevstate list";
00147 e->usage =
00148 "Usage: funcdevstate list\n"
00149 " List all custom device states that have been set by using\n"
00150 " the DEVICE_STATE dialplan function.\n";
00151 return NULL;
00152 case CLI_GENERATE:
00153 return NULL;
00154 }
00155
00156 if (a->argc != e->args)
00157 return CLI_SHOWUSAGE;
00158
00159 ast_cli(a->fd, "\n"
00160 "---------------------------------------------------------------------\n"
00161 "--- Custom Device States --------------------------------------------\n"
00162 "---------------------------------------------------------------------\n"
00163 "---\n");
00164
00165 db_entry = db_tree = ast_db_gettree(astdb_family, NULL);
00166 for (; db_entry; db_entry = db_entry->next) {
00167 const char *dev_name = strrchr(db_entry->key, '/') + 1;
00168 if (dev_name <= (const char *) 1)
00169 continue;
00170 ast_cli(a->fd, "--- Name: 'Custom:%s' State: '%s'\n"
00171 "---\n", dev_name, db_entry->data);
00172 }
00173 ast_db_freetree(db_tree);
00174 db_tree = NULL;
00175
00176 ast_cli(a->fd,
00177 "---------------------------------------------------------------------\n"
00178 "---------------------------------------------------------------------\n"
00179 "\n");
00180
00181 return CLI_SUCCESS;
00182 }
00183
00184 static char *handle_cli_devstate_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00185 {
00186 struct ast_db_entry *db_entry, *db_tree;
00187
00188 switch (cmd) {
00189 case CLI_INIT:
00190 e->command = "devstate list";
00191 e->usage =
00192 "Usage: devstate list\n"
00193 " List all custom device states that have been set by using\n"
00194 " the DEVICE_STATE dialplan function.\n";
00195 return NULL;
00196 case CLI_GENERATE:
00197 return NULL;
00198 }
00199
00200 if (a->argc != e->args)
00201 return CLI_SHOWUSAGE;
00202
00203 ast_cli(a->fd, "\n"
00204 "---------------------------------------------------------------------\n"
00205 "--- Custom Device States --------------------------------------------\n"
00206 "---------------------------------------------------------------------\n"
00207 "---\n");
00208
00209 db_entry = db_tree = ast_db_gettree(astdb_family, NULL);
00210 for (; db_entry; db_entry = db_entry->next) {
00211 const char *dev_name = strrchr(db_entry->key, '/') + 1;
00212 if (dev_name <= (const char *) 1)
00213 continue;
00214 ast_cli(a->fd, "--- Name: 'Custom:%s' State: '%s'\n"
00215 "---\n", dev_name, db_entry->data);
00216 }
00217 ast_db_freetree(db_tree);
00218 db_tree = NULL;
00219
00220 ast_cli(a->fd,
00221 "---------------------------------------------------------------------\n"
00222 "---------------------------------------------------------------------\n"
00223 "\n");
00224
00225 return CLI_SUCCESS;
00226 }
00227
00228 static char *handle_cli_devstate_change(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00229 {
00230 size_t len;
00231 const char *dev, *state;
00232 enum ast_device_state state_val;
00233
00234 switch (cmd) {
00235 case CLI_INIT:
00236 e->command = "devstate change";
00237 e->usage =
00238 "Usage: devstate change <device> <state>\n"
00239 " Change a custom device to a new state.\n"
00240 " The possible values for the state are:\n"
00241 "UNKNOWN | NOT_INUSE | INUSE | BUSY | INVALID | UNAVAILABLE | RINGING\n"
00242 "RINGINUSE | ONHOLD\n",
00243 "\n"
00244 "Examples:\n"
00245 " devstate change Custom:mystate1 INUSE\n"
00246 " devstate change Custom:mystate1 NOT_INUSE\n"
00247 " \n";
00248 return NULL;
00249 case CLI_GENERATE:
00250 {
00251 static char * const cmds[] = { "UNKNOWN", "NOT_INUSE", "INUSE", "BUSY",
00252 "UNAVAILABLE", "RINGING", "RINGINUSE", "ONHOLD", NULL };
00253
00254 if (a->pos == e->args + 1)
00255 return ast_cli_complete(a->word, cmds, a->n);
00256
00257 return NULL;
00258 }
00259 }
00260
00261 if (a->argc != e->args + 2)
00262 return CLI_SHOWUSAGE;
00263
00264 len = strlen("Custom:");
00265 dev = a->argv[e->args];
00266 state = a->argv[e->args + 1];
00267
00268 if (strncasecmp(dev, "Custom:", len)) {
00269 ast_cli(a->fd, "The devstate command can only be used to set 'Custom:' device state!\n");
00270 return CLI_FAILURE;
00271 }
00272
00273 dev += len;
00274 if (ast_strlen_zero(dev))
00275 return CLI_SHOWUSAGE;
00276
00277 state_val = ast_devstate_val(state);
00278
00279 if (state_val == AST_DEVICE_UNKNOWN)
00280 return CLI_SHOWUSAGE;
00281
00282 ast_cli(a->fd, "Changing %s to %s\n", dev, state);
00283
00284 ast_db_put(astdb_family, dev, state);
00285
00286 ast_devstate_changed(state_val, "Custom:%s", dev);
00287
00288 return CLI_SUCCESS;
00289 }
00290
00291 static struct ast_cli_entry cli_funcdevstate_list_deprecated = AST_CLI_DEFINE(handle_cli_funcdevstate_list, "List currently known custom device states");
00292 static struct ast_cli_entry cli_funcdevstate[] = {
00293 AST_CLI_DEFINE(handle_cli_devstate_list, "List currently known custom device states", .deprecate_cmd = &cli_funcdevstate_list_deprecated),
00294 AST_CLI_DEFINE(handle_cli_devstate_change, "Change a custom device state"),
00295 };
00296
00297 static struct ast_custom_function devstate_function = {
00298 .name = "DEVICE_STATE",
00299 .synopsis = "Get or Set a device state",
00300 .syntax = "DEVICE_STATE(device)",
00301 .desc =
00302 " The DEVICE_STATE function can be used to retrieve the device state from any\n"
00303 "device state provider. For example:\n"
00304 " NoOp(SIP/mypeer has state ${DEVICE_STATE(SIP/mypeer)})\n"
00305 " NoOp(Conference number 1234 has state ${DEVICE_STATE(MeetMe:1234)})\n"
00306 "\n"
00307 " The DEVICE_STATE function can also be used to set custom device state from\n"
00308 "the dialplan. The \"Custom:\" prefix must be used. For example:\n"
00309 " Set(DEVICE_STATE(Custom:lamp1)=BUSY)\n"
00310 " Set(DEVICE_STATE(Custom:lamp2)=NOT_INUSE)\n"
00311 "You can subscribe to the status of a custom device state using a hint in\n"
00312 "the dialplan:\n"
00313 " exten => 1234,hint,Custom:lamp1\n"
00314 "\n"
00315 " The possible values for both uses of this function are:\n"
00316 "UNKNOWN | NOT_INUSE | INUSE | BUSY | INVALID | UNAVAILABLE | RINGING\n"
00317 "RINGINUSE | ONHOLD\n",
00318 .read = devstate_read,
00319 .write = devstate_write,
00320 };
00321
00322 static struct ast_custom_function hint_function = {
00323 .name = "HINT",
00324 .synopsis = "Get the devices set for a dialplan hint",
00325 .syntax = "HINT(extension[@context][|options])",
00326 .desc =
00327 " The HINT function can be used to retrieve the list of devices that are\n"
00328 "mapped to a dialplan hint. For example:\n"
00329 " NoOp(Hint for Extension 1234 is ${HINT(1234)})\n"
00330 "Options:\n"
00331 " 'n' - Retrieve name on the hint instead of list of devices\n"
00332 "",
00333 .read = hint_read,
00334 };
00335
00336 static int unload_module(void)
00337 {
00338 int res = 0;
00339
00340 res |= ast_custom_function_unregister(&devstate_function);
00341 res |= ast_custom_function_unregister(&hint_function);
00342 res |= ast_devstate_prov_del("Custom");
00343 res |= ast_cli_unregister_multiple(cli_funcdevstate, ARRAY_LEN(cli_funcdevstate));
00344
00345 return res;
00346 }
00347
00348 static int load_module(void)
00349 {
00350 int res = 0;
00351 struct ast_db_entry *db_entry, *db_tree;
00352
00353
00354
00355 db_entry = db_tree = ast_db_gettree(astdb_family, NULL);
00356 for (; db_entry; db_entry = db_entry->next) {
00357 const char *dev_name = strrchr(db_entry->key, '/') + 1;
00358 if (dev_name <= (const char *) 1)
00359 continue;
00360 ast_devstate_changed(ast_devstate_val(db_entry->data),
00361 "Custom:%s\n", dev_name);
00362 }
00363 ast_db_freetree(db_tree);
00364 db_tree = NULL;
00365
00366 res |= ast_custom_function_register(&devstate_function);
00367 res |= ast_custom_function_register(&hint_function);
00368 res |= ast_devstate_prov_add("Custom", custom_devstate_callback);
00369 res |= ast_cli_register_multiple(cli_funcdevstate, ARRAY_LEN(cli_funcdevstate));
00370
00371 return res;
00372 }
00373
00374 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Gets or sets a device state in the dialplan");