Thu Jul 9 13:40:35 2009

Asterisk developer's documentation


func_devstate.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2007, Digium, Inc.
00005  *
00006  * Russell Bryant <russell@digium.com> 
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Manually controlled blinky lights
00022  *
00023  * \author Russell Bryant <russell@digium.com> 
00024  *
00025  * \ingroup functions
00026  *
00027  * \note Props go out to Ahrimanes in \#asterisk for requesting this at 4:30 AM
00028  *       when I couldn't sleep.  :)
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; /* ast_get_hint returns non-zero on success */
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    /* Populate the device state cache on the system with all of the currently
00352     * known custom device states. */
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");

Generated on Thu Jul 9 13:40:35 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7