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