diff options
-rw-r--r-- | .cleancount | 2 | ||||
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | include/asterisk/_private.h | 1 | ||||
-rw-r--r-- | include/asterisk/features.h | 3 | ||||
-rw-r--r-- | main/Makefile | 3 | ||||
-rw-r--r-- | main/asterisk.c | 3 | ||||
-rw-r--r-- | main/features.c (renamed from res/res_features.c) | 699 | ||||
-rw-r--r-- | main/loader.c | 2 |
8 files changed, 359 insertions, 357 deletions
diff --git a/.cleancount b/.cleancount index bb95160cb..a78736459 100644 --- a/.cleancount +++ b/.cleancount @@ -1 +1 @@ -33 +34 @@ -409,6 +409,8 @@ Call Features (res_features) Changes * Updated the ParkedCall application to allow you to not specify a parking extension. If you don't specify a parking space to pick up, it will grab the first one available. + * Added cli command 'features reload' to reload call features from features.conf + * Moved into core asterisk binary. Language Support Changes ------------------------ @@ -498,4 +500,3 @@ Miscellaneous specifying which socket to use to connect to the running Asterisk daemon (-s) * Added logging to 'make update' command. See update.log - diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h index 06163cd53..33ba83593 100644 --- a/include/asterisk/_private.h +++ b/include/asterisk/_private.h @@ -32,6 +32,7 @@ void ast_event_init(void); /*!< Provided by event.c */ int ast_device_state_engine_init(void); /*!< Provided by devicestate.c */ int astobj2_init(void); /*!< Provided by astobj2.c */ int ast_file_init(void); /*!< Provided by file.c */ +int ast_features_init(void); /*!< Provided by features.c */ /*! * \brief Reload asterisk modules. diff --git a/include/asterisk/features.h b/include/asterisk/features.h index aa145a961..6e2ae1eab 100644 --- a/include/asterisk/features.h +++ b/include/asterisk/features.h @@ -109,4 +109,7 @@ struct ast_call_feature *ast_find_call_feature(const char *name); void ast_rdlock_call_features(void); void ast_unlock_call_features(void); +/*! \brief Reload call features from features.conf */ +int ast_features_reload(void); + #endif /* _AST_FEATURES_H */ diff --git a/main/Makefile b/main/Makefile index 3504b547b..15d793fb5 100644 --- a/main/Makefile +++ b/main/Makefile @@ -29,7 +29,8 @@ OBJS= tcptls.o io.o sched.o logger.o frame.o loader.o config.o channel.o \ netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \ cryptostub.o sha1.o http.o fixedjitterbuf.o abstract_jb.o \ strcompat.o threadstorage.o dial.o event.o adsistub.o audiohook.o \ - astobj2.o hashtab.o global_datastores.o $(RESAMPLE_OBJS) version.o + astobj2.o hashtab.o global_datastores.o $(RESAMPLE_OBJS) version.o \ + features.o # we need to link in the objects statically, not as a library, because # otherwise modules will not have them available if none of the static diff --git a/main/asterisk.c b/main/asterisk.c index 4c903cfbe..45bfc808c 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -96,6 +96,7 @@ int daemon(int, int); /* defined in libresolv of all places */ #include "asterisk/network.h" #include "asterisk/cli.h" #include "asterisk/channel.h" +#include "asterisk/features.h" #include "asterisk/ulaw.h" #include "asterisk/alaw.h" #include "asterisk/callerid.h" @@ -3165,6 +3166,8 @@ int main(int argc, char *argv[]) exit(1); } + ast_features_init(); + if (init_framer()) { printf(term_quit()); exit(1); diff --git a/res/res_features.c b/main/features.c index c6f68124e..c0c77c26d 100644 --- a/res/res_features.c +++ b/main/features.c @@ -1,7 +1,7 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 1999 - 2006, Digium, Inc. + * Copyright (C) 1999 - 2008, Digium, Inc. * * Mark Spencer <markster@digium.com> * @@ -31,6 +31,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +#include "asterisk/_private.h" + #include <pthread.h> #include <sys/time.h> #include <sys/signal.h> @@ -126,7 +128,7 @@ static unsigned int atxferdropcall; static unsigned int atxferloopdelay; static unsigned int atxfercallbackretries; -static char *registrar = "res_features"; /*!< Registrar for operations */ +static char *registrar = "features"; /*!< Registrar for operations */ /* module and CLI command definitions */ static char *synopsis = "Answer a parked call"; @@ -599,9 +601,6 @@ static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_channel *parker; struct ast_channel *parkee; int res = 0; - struct ast_module_user *u; - - u = ast_module_user_add(chan); set_peers(&parker, &parkee, peer, chan, sense); /* Setup the exten/priority to be s/1 since we don't know @@ -615,8 +614,6 @@ static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, if (!res) res = ast_park_call(parkee, parker, 0, NULL); - ast_module_user_remove(u); - if (!res) { if (sense == FEATURE_SENSE_CHAN) res = AST_PBX_NO_HANGUP_PEER; @@ -675,7 +672,7 @@ static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *pee if (callee_chan->monitor) { ast_verb(4, "User hit '%s' to stop recording call.\n", code); - ast_monitor_stop(callee_chan, 1); + callee_chan->monitor->stop(callee_chan, 1); return FEATURE_RETURN_SUCCESS; } @@ -2511,6 +2508,315 @@ static int park_exec(struct ast_channel *chan, void *data) return res; } +/*! + * \brief Add parking hints for all defined parking lots + * \param context + * \param start starting parkinglot number + * \param stop ending parkinglot number +*/ +static void park_add_hints(char *context, int start, int stop) +{ + int numext; + char device[AST_MAX_EXTENSION]; + char exten[10]; + + for (numext = start; numext <= stop; numext++) { + snprintf(exten, sizeof(exten), "%d", numext); + snprintf(device, sizeof(device), "park:%s@%s", exten, context); + ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); + } +} + +static int load_config(void) +{ + int start = 0, end = 0; + int res; + int i; + struct ast_context *con = NULL; + struct ast_config *cfg = NULL; + struct ast_variable *var = NULL; + struct feature_group *fg = NULL; + struct ast_flags config_flags = { 0 }; + char old_parking_ext[AST_MAX_EXTENSION]; + char old_parking_con[AST_MAX_EXTENSION] = ""; + char *ctg; + static const char *categories[] = { + /* Categories in features.conf that are not + * to be parsed as group categories + */ + "general", + "featuremap", + "applicationmap" + }; + + if (!ast_strlen_zero(parking_con)) { + strcpy(old_parking_ext, parking_ext); + strcpy(old_parking_con, parking_con); + } + + /* Reset to defaults */ + strcpy(parking_con, "parkedcalls"); + strcpy(parking_con_dial, "park-dial"); + strcpy(parking_ext, "700"); + strcpy(pickup_ext, "*8"); + strcpy(parkmohclass, "default"); + courtesytone[0] = '\0'; + strcpy(xfersound, "beep"); + strcpy(xferfailsound, "pbx-invalid"); + parking_start = 701; + parking_stop = 750; + parkfindnext = 0; + adsipark = 0; + comebacktoorigin = 1; + parkaddhints = 0; + parkedcalltransfers = 0; + parkedcallreparking = 0; + + transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; + featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; + atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; + atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; + atxferdropcall = DEFAULT_ATXFER_DROP_CALL; + atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; + + cfg = ast_config_load("features.conf", config_flags); + if (!cfg) { + ast_log(LOG_WARNING,"Could not load features.conf\n"); + return 0; + } + for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { + if (!strcasecmp(var->name, "parkext")) { + ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); + } else if (!strcasecmp(var->name, "context")) { + ast_copy_string(parking_con, var->value, sizeof(parking_con)); + } else if (!strcasecmp(var->name, "parkingtime")) { + if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) { + ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); + parkingtime = DEFAULT_PARK_TIME; + } else + parkingtime = parkingtime * 1000; + } else if (!strcasecmp(var->name, "parkpos")) { + if (sscanf(var->value, "%d-%d", &start, &end) != 2) { + ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of features.conf\n", var->lineno); + } else { + parking_start = start; + parking_stop = end; + } + } else if (!strcasecmp(var->name, "findslot")) { + parkfindnext = (!strcasecmp(var->value, "next")); + } else if (!strcasecmp(var->name, "parkinghints")) { + parkaddhints = ast_true(var->value); + } else if (!strcasecmp(var->name, "parkedcalltransfers")) { + if (!strcasecmp(var->value, "both")) + parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; + else if (!strcasecmp(var->value, "caller")) + parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; + else if (!strcasecmp(var->value, "callee")) + parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; + } else if (!strcasecmp(var->name, "parkedcallreparking")) { + if (!strcasecmp(var->value, "both")) + parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; + else if (!strcasecmp(var->value, "caller")) + parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; + else if (!strcasecmp(var->value, "callee")) + parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; + } else if (!strcasecmp(var->name, "adsipark")) { + adsipark = ast_true(var->value); + } else if (!strcasecmp(var->name, "transferdigittimeout")) { + if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { + ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); + transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; + } else + transferdigittimeout = transferdigittimeout * 1000; + } else if (!strcasecmp(var->name, "featuredigittimeout")) { + if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { + ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); + featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; + } + } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { + if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { + ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); + atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; + } else + atxfernoanswertimeout = atxfernoanswertimeout * 1000; + } else if (!strcasecmp(var->name, "atxferloopdelay")) { + if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) { + ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value); + atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; + } else + atxferloopdelay *= 1000; + } else if (!strcasecmp(var->name, "atxferdropcall")) { + atxferdropcall = ast_true(var->value); + } else if (!strcasecmp(var->name, "atxfercallbackretries")) { + if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) { + ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value); + atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; + } + } else if (!strcasecmp(var->name, "courtesytone")) { + ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); + } else if (!strcasecmp(var->name, "parkedplay")) { + if (!strcasecmp(var->value, "both")) + parkedplay = 2; + else if (!strcasecmp(var->value, "parked")) + parkedplay = 1; + else + parkedplay = 0; + } else if (!strcasecmp(var->name, "xfersound")) { + ast_copy_string(xfersound, var->value, sizeof(xfersound)); + } else if (!strcasecmp(var->name, "xferfailsound")) { + ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); + } else if (!strcasecmp(var->name, "pickupexten")) { + ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); + } else if (!strcasecmp(var->name, "comebacktoorigin")) { + comebacktoorigin = ast_true(var->value); + } else if (!strcasecmp(var->name, "parkedmusicclass")) { + ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass)); + } + } + + unmap_features(); + for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { + if (remap_feature(var->name, var->value)) + ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); + } + + /* Map a key combination to an application*/ + ast_unregister_features(); + for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { + char *tmp_val = ast_strdupa(var->value); + char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; + struct ast_call_feature *feature; + + /* strsep() sets the argument to NULL if match not found, and it + * is safe to use it with a NULL argument, so we don't check + * between calls. + */ + exten = strsep(&tmp_val,","); + activatedby = strsep(&tmp_val,","); + app = strsep(&tmp_val,","); + app_args = strsep(&tmp_val,","); + moh_class = strsep(&tmp_val,","); + + activateon = strsep(&activatedby, "/"); + + /*! \todo XXX var_name or app_args ? */ + if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { + ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", + app, exten, activateon, var->name); + continue; + } + + AST_LIST_LOCK(&feature_list); + if ((feature = find_dynamic_feature(var->name))) { + AST_LIST_UNLOCK(&feature_list); + ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); + continue; + } + AST_LIST_UNLOCK(&feature_list); + + if (!(feature = ast_calloc(1, sizeof(*feature)))) + continue; + + ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); + ast_copy_string(feature->app, app, FEATURE_APP_LEN); + ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); + + if (app_args) + ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); + + if (moh_class) + ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); + + ast_copy_string(feature->exten, exten, sizeof(feature->exten)); + feature->operation = feature_exec_app; + ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); + + /* Allow caller and calle to be specified for backwards compatability */ + if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) + ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); + else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) + ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); + else { + ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," + " must be 'self', or 'peer'\n", var->name); + continue; + } + + if (ast_strlen_zero(activatedby)) + ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); + else if (!strcasecmp(activatedby, "caller")) + ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); + else if (!strcasecmp(activatedby, "callee")) + ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); + else if (!strcasecmp(activatedby, "both")) + ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); + else { + ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," + " must be 'caller', or 'callee', or 'both'\n", var->name); + continue; + } + + ast_register_feature(feature); + + ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); + } + + ast_unregister_groups(); + AST_RWLIST_WRLOCK(&feature_groups); + + ctg = NULL; + while ((ctg = ast_category_browse(cfg, ctg))) { + for (i = 0; i < ARRAY_LEN(categories); i++) { + if (!strcasecmp(categories[i], ctg)) + break; + } + + if (i < ARRAY_LEN(categories)) + continue; + + if (!(fg = register_group(ctg))) + continue; + + for (var = ast_variable_browse(cfg, ctg); var; var = var->next) { + struct ast_call_feature *feature; + + AST_LIST_LOCK(&feature_list); + if(!(feature = find_dynamic_feature(var->name)) && + !(feature = ast_find_call_feature(var->name))) { + AST_LIST_UNLOCK(&feature_list); + ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name); + continue; + } + AST_LIST_UNLOCK(&feature_list); + + register_group_feature(fg, var->value, feature); + } + } + + AST_RWLIST_UNLOCK(&feature_groups); + + ast_config_destroy(cfg); + + /* Remove the old parking extension */ + if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { + if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar)) + notify_metermaids(old_parking_ext, old_parking_con, AST_DEVICE_NOT_INUSE); + ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); + } + + if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) { + ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); + return -1; + } + res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); + if (parkaddhints) + park_add_hints(parking_con, parking_start, parking_stop); + if (!res) + notify_metermaids(ast_parking_ext(), parking_con, AST_DEVICE_INUSE); + return res; + +} + /*! * \brief CLI command to list configured features * \param e @@ -2520,7 +2826,8 @@ static int park_exec(struct ast_channel *chan, void *data) * \retval CLI_SUCCESS on success. * \retval NULL when tab completion is used. */ -static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { +static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ int i; struct ast_call_feature *feature; char format[] = "%-25s %-7s %-7s\n"; @@ -2568,6 +2875,30 @@ static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cl return CLI_SUCCESS; } +int ast_features_reload(void) +{ + load_config(); + + return RESULT_SUCCESS; +} + +static char *handle_features_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + switch (cmd) { + case CLI_INIT: + e->command = "features reload"; + e->usage = + "Usage: features reload\n" + " Reloads configured call features from features.conf\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + load_config(); + + return CLI_SUCCESS; +} + static char mandescr_bridge[] = "Description: Bridge together two channels already in the PBX\n" "Variables: ( Headers marked with * are required )\n" @@ -2769,6 +3100,7 @@ static struct ast_cli_entry cli_show_parkedcalls_deprecated = AST_CLI_DEFINE(han static struct ast_cli_entry cli_features[] = { AST_CLI_DEFINE(handle_feature_show, "Lists configured features"), + AST_CLI_DEFINE(handle_features_reload, "Reloads configured features"), AST_CLI_DEFINE(handle_parkedcalls, "List currently parked calls", .deprecate_cmd = &cli_show_parkedcalls_deprecated), }; @@ -2930,316 +3262,6 @@ int ast_pickup_call(struct ast_channel *chan) return res; } -/*! - * \brief Add parking hints for all defined parking lots - * \param context - * \param start starting parkinglot number - * \param stop ending parkinglot number -*/ -static void park_add_hints(char *context, int start, int stop) -{ - int numext; - char device[AST_MAX_EXTENSION]; - char exten[10]; - - for (numext = start; numext <= stop; numext++) { - snprintf(exten, sizeof(exten), "%d", numext); - snprintf(device, sizeof(device), "park:%s@%s", exten, context); - ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); - } -} - - -static int load_config(void) -{ - int start = 0, end = 0; - int res; - int i; - struct ast_context *con = NULL; - struct ast_config *cfg = NULL; - struct ast_variable *var = NULL; - struct feature_group *fg = NULL; - struct ast_flags config_flags = { 0 }; - char old_parking_ext[AST_MAX_EXTENSION]; - char old_parking_con[AST_MAX_EXTENSION] = ""; - char *ctg; - static const char *categories[] = { - /* Categories in features.conf that are not - * to be parsed as group categories - */ - "general", - "featuremap", - "applicationmap" - }; - - if (!ast_strlen_zero(parking_con)) { - strcpy(old_parking_ext, parking_ext); - strcpy(old_parking_con, parking_con); - } - - /* Reset to defaults */ - strcpy(parking_con, "parkedcalls"); - strcpy(parking_con_dial, "park-dial"); - strcpy(parking_ext, "700"); - strcpy(pickup_ext, "*8"); - strcpy(parkmohclass, "default"); - courtesytone[0] = '\0'; - strcpy(xfersound, "beep"); - strcpy(xferfailsound, "pbx-invalid"); - parking_start = 701; - parking_stop = 750; - parkfindnext = 0; - adsipark = 0; - comebacktoorigin = 1; - parkaddhints = 0; - parkedcalltransfers = 0; - parkedcallreparking = 0; - - transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; - featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; - atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; - atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; - atxferdropcall = DEFAULT_ATXFER_DROP_CALL; - atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; - - cfg = ast_config_load("features.conf", config_flags); - if (!cfg) { - ast_log(LOG_WARNING,"Could not load features.conf\n"); - return AST_MODULE_LOAD_DECLINE; - } - for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { - if (!strcasecmp(var->name, "parkext")) { - ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); - } else if (!strcasecmp(var->name, "context")) { - ast_copy_string(parking_con, var->value, sizeof(parking_con)); - } else if (!strcasecmp(var->name, "parkingtime")) { - if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) { - ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); - parkingtime = DEFAULT_PARK_TIME; - } else - parkingtime = parkingtime * 1000; - } else if (!strcasecmp(var->name, "parkpos")) { - if (sscanf(var->value, "%d-%d", &start, &end) != 2) { - ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of features.conf\n", var->lineno); - } else { - parking_start = start; - parking_stop = end; - } - } else if (!strcasecmp(var->name, "findslot")) { - parkfindnext = (!strcasecmp(var->value, "next")); - } else if (!strcasecmp(var->name, "parkinghints")) { - parkaddhints = ast_true(var->value); - } else if (!strcasecmp(var->name, "parkedcalltransfers")) { - if (!strcasecmp(var->value, "both")) - parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; - else if (!strcasecmp(var->value, "caller")) - parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; - else if (!strcasecmp(var->value, "callee")) - parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; - } else if (!strcasecmp(var->name, "parkedcallreparking")) { - if (!strcasecmp(var->value, "both")) - parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; - else if (!strcasecmp(var->value, "caller")) - parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; - else if (!strcasecmp(var->value, "callee")) - parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; - } else if (!strcasecmp(var->name, "adsipark")) { - adsipark = ast_true(var->value); - } else if (!strcasecmp(var->name, "transferdigittimeout")) { - if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { - ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); - transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; - } else - transferdigittimeout = transferdigittimeout * 1000; - } else if (!strcasecmp(var->name, "featuredigittimeout")) { - if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { - ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); - featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; - } - } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { - if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { - ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); - atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; - } else - atxfernoanswertimeout = atxfernoanswertimeout * 1000; - } else if (!strcasecmp(var->name, "atxferloopdelay")) { - if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) { - ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value); - atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; - } else - atxferloopdelay *= 1000; - } else if (!strcasecmp(var->name, "atxferdropcall")) { - atxferdropcall = ast_true(var->value); - } else if (!strcasecmp(var->name, "atxfercallbackretries")) { - if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) { - ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value); - atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; - } - } else if (!strcasecmp(var->name, "courtesytone")) { - ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); - } else if (!strcasecmp(var->name, "parkedplay")) { - if (!strcasecmp(var->value, "both")) - parkedplay = 2; - else if (!strcasecmp(var->value, "parked")) - parkedplay = 1; - else - parkedplay = 0; - } else if (!strcasecmp(var->name, "xfersound")) { - ast_copy_string(xfersound, var->value, sizeof(xfersound)); - } else if (!strcasecmp(var->name, "xferfailsound")) { - ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); - } else if (!strcasecmp(var->name, "pickupexten")) { - ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); - } else if (!strcasecmp(var->name, "comebacktoorigin")) { - comebacktoorigin = ast_true(var->value); - } else if (!strcasecmp(var->name, "parkedmusicclass")) { - ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass)); - } - } - - unmap_features(); - for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { - if (remap_feature(var->name, var->value)) - ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); - } - - /* Map a key combination to an application*/ - ast_unregister_features(); - for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { - char *tmp_val = ast_strdupa(var->value); - char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; - struct ast_call_feature *feature; - - /* strsep() sets the argument to NULL if match not found, and it - * is safe to use it with a NULL argument, so we don't check - * between calls. - */ - exten = strsep(&tmp_val,","); - activatedby = strsep(&tmp_val,","); - app = strsep(&tmp_val,","); - app_args = strsep(&tmp_val,","); - moh_class = strsep(&tmp_val,","); - - activateon = strsep(&activatedby, "/"); - - /*! \todo XXX var_name or app_args ? */ - if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { - ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", - app, exten, activateon, var->name); - continue; - } - - AST_LIST_LOCK(&feature_list); - if ((feature = find_dynamic_feature(var->name))) { - AST_LIST_UNLOCK(&feature_list); - ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); - continue; - } - AST_LIST_UNLOCK(&feature_list); - - if (!(feature = ast_calloc(1, sizeof(*feature)))) - continue; - - ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); - ast_copy_string(feature->app, app, FEATURE_APP_LEN); - ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); - - if (app_args) - ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); - - if (moh_class) - ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); - - ast_copy_string(feature->exten, exten, sizeof(feature->exten)); - feature->operation = feature_exec_app; - ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); - - /* Allow caller and calle to be specified for backwards compatability */ - if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) - ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); - else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) - ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); - else { - ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," - " must be 'self', or 'peer'\n", var->name); - continue; - } - - if (ast_strlen_zero(activatedby)) - ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); - else if (!strcasecmp(activatedby, "caller")) - ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); - else if (!strcasecmp(activatedby, "callee")) - ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); - else if (!strcasecmp(activatedby, "both")) - ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); - else { - ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," - " must be 'caller', or 'callee', or 'both'\n", var->name); - continue; - } - - ast_register_feature(feature); - - ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); - } - - ast_unregister_groups(); - AST_RWLIST_WRLOCK(&feature_groups); - - ctg = NULL; - while ((ctg = ast_category_browse(cfg, ctg))) { - for (i = 0; i < ARRAY_LEN(categories); i++) { - if (!strcasecmp(categories[i], ctg)) - break; - } - - if (i < ARRAY_LEN(categories)) - continue; - - if (!(fg = register_group(ctg))) - continue; - - for (var = ast_variable_browse(cfg, ctg); var; var = var->next) { - struct ast_call_feature *feature; - - AST_LIST_LOCK(&feature_list); - if(!(feature = find_dynamic_feature(var->name)) && - !(feature = ast_find_call_feature(var->name))) { - AST_LIST_UNLOCK(&feature_list); - ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name); - continue; - } - AST_LIST_UNLOCK(&feature_list); - - register_group_feature(fg, var->value, feature); - } - } - - AST_RWLIST_UNLOCK(&feature_groups); - - ast_config_destroy(cfg); - - /* Remove the old parking extension */ - if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { - if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar)) - notify_metermaids(old_parking_ext, old_parking_con, AST_DEVICE_NOT_INUSE); - ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); - } - - if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) { - ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); - return -1; - } - res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); - if (parkaddhints) - park_add_hints(parking_con, parking_start, parking_stop); - if (!res) - notify_metermaids(ast_parking_ext(), parking_con, AST_DEVICE_INUSE); - return res; - -} - static char *app_bridge = "Bridge"; static char *bridge_synopsis = "Bridge two channels"; static char *bridge_descrip = @@ -3388,16 +3410,11 @@ static int bridge_exec(struct ast_channel *chan, void *data) return 0; } -static int reload(void) -{ - return load_config(); -} - -static int load_module(void) +int ast_features_init(void) { int res; - ast_register_application(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip); + ast_register_application2(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip, NULL); memset(parking_ext, 0, sizeof(parking_ext)); memset(parking_con, 0, sizeof(parking_con)); @@ -3406,9 +3423,9 @@ static int load_module(void) return res; ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); - res = ast_register_application(parkedcall, park_exec, synopsis, descrip); + res = ast_register_application2(parkedcall, park_exec, synopsis, descrip, NULL); if (!res) - res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2); + res = ast_register_application2(parkcall, park_call_exec, synopsis2, descrip2, NULL); if (!res) { ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls"); ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, @@ -3420,29 +3437,3 @@ static int load_module(void) return res; } - - -static int unload_module(void) -{ - struct ast_context *con; - ast_manager_unregister("ParkedCalls"); - ast_manager_unregister("Bridge"); - ast_manager_unregister("Park"); - ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); - ast_unregister_application(parkcall); - ast_unregister_application(app_bridge); - ast_devstate_prov_del("Park"); - con = ast_context_find(parking_con); - if (con) - ast_context_destroy(con, registrar); - con = ast_context_find(parking_con_dial); - if (con) - ast_context_destroy(con, registrar); - return ast_unregister_application(parkedcall); -} - -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Features Resource", - .load = load_module, - .unload = unload_module, - .reload = reload, - ); diff --git a/main/loader.c b/main/loader.c index 1d0797720..45fc7be82 100644 --- a/main/loader.c +++ b/main/loader.c @@ -46,6 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/rtp.h" #include "asterisk/http.h" #include "asterisk/lock.h" +#include "asterisk/features.h" #ifdef DLFCNCOMPAT #include "asterisk/dlfcn-compat.h" @@ -247,6 +248,7 @@ static struct reload_classes { { "rtp", ast_rtp_reload }, { "http", ast_http_reload }, { "logger", logger_reload }, + { "features", ast_features_reload }, { NULL, NULL } }; |