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: 378303 $")
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, AST_DEVSTATE_CACHABLE, "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
00191 ast_db_get(astdb_family, data, buf, sizeof(buf));
00192
00193 return ast_devstate_val(buf);
00194 }
00195
00196 static char *handle_cli_devstate_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00197 {
00198 struct ast_db_entry *db_entry, *db_tree;
00199
00200 switch (cmd) {
00201 case CLI_INIT:
00202 e->command = "devstate list";
00203 e->usage =
00204 "Usage: devstate list\n"
00205 " List all custom device states that have been set by using\n"
00206 " the DEVICE_STATE dialplan function.\n";
00207 return NULL;
00208 case CLI_GENERATE:
00209 return NULL;
00210 }
00211
00212 if (a->argc != e->args)
00213 return CLI_SHOWUSAGE;
00214
00215 ast_cli(a->fd, "\n"
00216 "---------------------------------------------------------------------\n"
00217 "--- Custom Device States --------------------------------------------\n"
00218 "---------------------------------------------------------------------\n"
00219 "---\n");
00220
00221 db_entry = db_tree = ast_db_gettree(astdb_family, NULL);
00222 for (; db_entry; db_entry = db_entry->next) {
00223 const char *dev_name = strrchr(db_entry->key, '/') + 1;
00224 if (dev_name <= (const char *) 1)
00225 continue;
00226 ast_cli(a->fd, "--- Name: 'Custom:%s' State: '%s'\n"
00227 "---\n", dev_name, db_entry->data);
00228 }
00229 ast_db_freetree(db_tree);
00230 db_tree = NULL;
00231
00232 ast_cli(a->fd,
00233 "---------------------------------------------------------------------\n"
00234 "---------------------------------------------------------------------\n"
00235 "\n");
00236
00237 return CLI_SUCCESS;
00238 }
00239
00240 static char *handle_cli_devstate_change(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00241 {
00242 size_t len;
00243 const char *dev, *state;
00244 enum ast_device_state state_val;
00245
00246 switch (cmd) {
00247 case CLI_INIT:
00248 e->command = "devstate change";
00249 e->usage =
00250 "Usage: devstate change <device> <state>\n"
00251 " Change a custom device to a new state.\n"
00252 " The possible values for the state are:\n"
00253 "UNKNOWN | NOT_INUSE | INUSE | BUSY | INVALID | UNAVAILABLE | RINGING\n"
00254 "RINGINUSE | ONHOLD\n"
00255 "\n"
00256 "Examples:\n"
00257 " devstate change Custom:mystate1 INUSE\n"
00258 " devstate change Custom:mystate1 NOT_INUSE\n"
00259 " \n";
00260 return NULL;
00261 case CLI_GENERATE:
00262 {
00263 static const char * const cmds[] = { "UNKNOWN", "NOT_INUSE", "INUSE", "BUSY",
00264 "UNAVAILABLE", "RINGING", "RINGINUSE", "ONHOLD", NULL };
00265
00266 if (a->pos == e->args + 1)
00267 return ast_cli_complete(a->word, cmds, a->n);
00268
00269 return NULL;
00270 }
00271 }
00272
00273 if (a->argc != e->args + 2)
00274 return CLI_SHOWUSAGE;
00275
00276 len = strlen("Custom:");
00277 dev = a->argv[e->args];
00278 state = a->argv[e->args + 1];
00279
00280 if (strncasecmp(dev, "Custom:", len)) {
00281 ast_cli(a->fd, "The devstate command can only be used to set 'Custom:' device state!\n");
00282 return CLI_FAILURE;
00283 }
00284
00285 dev += len;
00286 if (ast_strlen_zero(dev))
00287 return CLI_SHOWUSAGE;
00288
00289 state_val = ast_devstate_val(state);
00290
00291 if (state_val == AST_DEVICE_UNKNOWN)
00292 return CLI_SHOWUSAGE;
00293
00294 ast_cli(a->fd, "Changing %s to %s\n", dev, state);
00295
00296 ast_db_put(astdb_family, dev, state);
00297
00298 ast_devstate_changed(state_val, AST_DEVSTATE_CACHABLE, "Custom:%s", dev);
00299
00300 return CLI_SUCCESS;
00301 }
00302
00303 static struct ast_cli_entry cli_funcdevstate[] = {
00304 AST_CLI_DEFINE(handle_cli_devstate_list, "List currently known custom device states"),
00305 AST_CLI_DEFINE(handle_cli_devstate_change, "Change a custom device state"),
00306 };
00307
00308 static struct ast_custom_function devstate_function = {
00309 .name = "DEVICE_STATE",
00310 .read = devstate_read,
00311 .write = devstate_write,
00312 };
00313
00314 static struct ast_custom_function hint_function = {
00315 .name = "HINT",
00316 .read = hint_read,
00317 };
00318
00319 static int unload_module(void)
00320 {
00321 int res = 0;
00322
00323 res |= ast_custom_function_unregister(&devstate_function);
00324 res |= ast_custom_function_unregister(&hint_function);
00325 res |= ast_devstate_prov_del("Custom");
00326 res |= ast_cli_unregister_multiple(cli_funcdevstate, ARRAY_LEN(cli_funcdevstate));
00327
00328 return res;
00329 }
00330
00331 static int load_module(void)
00332 {
00333 int res = 0;
00334 struct ast_db_entry *db_entry, *db_tree;
00335
00336
00337
00338 db_entry = db_tree = ast_db_gettree(astdb_family, NULL);
00339 for (; db_entry; db_entry = db_entry->next) {
00340 const char *dev_name = strrchr(db_entry->key, '/') + 1;
00341 if (dev_name <= (const char *) 1)
00342 continue;
00343 ast_devstate_changed(ast_devstate_val(db_entry->data),
00344 AST_DEVSTATE_CACHABLE, "Custom:%s\n", dev_name);
00345 }
00346 ast_db_freetree(db_tree);
00347 db_tree = NULL;
00348
00349 res |= ast_custom_function_register(&devstate_function);
00350 res |= ast_custom_function_register(&hint_function);
00351 res |= ast_devstate_prov_add("Custom", custom_devstate_callback);
00352 res |= ast_cli_register_multiple(cli_funcdevstate, ARRAY_LEN(cli_funcdevstate));
00353
00354 return res;
00355 }
00356
00357 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Gets or sets a device state in the dialplan",
00358 .load = load_module,
00359 .unload = unload_module,
00360 .load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
00361 );