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