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