Index: main/features.c =================================================================== --- main/features.c (revision 216221) +++ main/features.c (working copy) @@ -149,6 +149,14 @@ If you set the PARKINGEXTEN variable to an extension in your parking context, Park() will park the call on that extension, unless it already exists. In that case, execution will continue at next priority. + If you set the PARKINGLOT variable, Park() will park the call + in that parkinglot. + If you set the PARKINGDYNAMIC variable, this parkinglot from features.conf + will be used as template for the newly created dynamically lot. + If you set the PARKINGDYNCONTEXT variable the newly created dynamic + parking lot will use this context. + If you set the PARKINGDYNPOS variable the newly created dynamic parkinglot + will use those parking postitions. ParkAndAnnounce @@ -293,6 +301,7 @@ static char courtesytone[256]; /*!< Courtesy tone */ static int parkedplay = 0; /*!< Who to play the courtesy tone to */ +static int parkeddynamic = 0; /*!< Enable creation of parkinglots dynamically */ static char xfersound[256]; /*!< Call transfer sound */ static char xferfailsound[256]; /*!< Call transfer failure sound */ static char pickupsound[256]; /*!< Pickup sound */ @@ -363,8 +372,9 @@ static void parkinglot_destroy(void *obj); int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *fs, int *max); struct ast_parkinglot *find_parkinglot(const char *name); +static struct ast_parkinglot *create_parkinglot(const char *name); +static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot); - const char *ast_parking_ext(void) { return parking_ext; @@ -616,23 +626,59 @@ struct parkeduser *pu; }; -static struct parkeduser *park_space_reserve(struct ast_channel *chan, - struct ast_channel *peer, struct ast_park_call_args *args) +static struct parkeduser *park_space_reserve(struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args) { struct parkeduser *pu; int i, parking_space = -1, parking_range; const char *parkinglotname = NULL; const char *parkingexten; struct ast_parkinglot *parkinglot = NULL; - + if (peer) parkinglotname = findparkinglotname(peer); if (parkinglotname) { - if (option_debug) - ast_log(LOG_DEBUG, "Found chanvar Parkinglot: %s\n", parkinglotname); - parkinglot = find_parkinglot(parkinglotname); + ast_debug(1, "Found chanvar Parkinglot: %s\n", parkinglotname); + parkinglot = find_parkinglot(parkinglotname); } + + if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) { /* Dynamically create parkinglot */ + const char *dyn_context, *dyn_range; + const char *parkinglotname_copy = NULL; + struct ast_parkinglot *parkinglot_copy = NULL; + int dyn_start, dyn_end; + + ast_channel_lock(chan); + parkinglotname_copy = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), "")); + dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), "")); + dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), "")); + ast_channel_unlock(chan); + + if (!ast_strlen_zero(parkinglotname_copy)) { + parkinglot_copy = find_parkinglot(parkinglotname_copy); + } + if (!parkinglot_copy) { + parkinglot_copy = default_parkinglot; + ast_debug(1, "Using default parking lot for copy\n"); + } + if (!(parkinglot = copy_parkinglot(parkinglotname, parkinglot_copy))) { + ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n"); + } else { + if (!ast_strlen_zero(dyn_context)) { + ast_copy_string(parkinglot->parking_con, dyn_context, sizeof(parkinglot->parking_con)); + } + if (!ast_strlen_zero(dyn_range)) { + if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) { + ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers\n"); + } else { + parkinglot->parking_start = dyn_start; + parkinglot->parking_stop = dyn_end; + } + } + ao2_link(parkinglots, parkinglot); + } + } + if (!parkinglot) parkinglot = default_parkinglot; @@ -650,7 +696,7 @@ AST_LIST_LOCK(&parkinglot->parkings); /* Check for channel variable PARKINGEXTEN */ ast_channel_lock(chan); - parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"); + parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"), "")); ast_channel_unlock(chan); if (!ast_strlen_zero(parkingexten)) { /*!\note The API forces us to specify a numeric parking slot, even @@ -3439,6 +3485,27 @@ return parkinglot; } +/*! \brief Copy parkinglot and store it with new name */ +struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot) { + struct ast_parkinglot *copylot; + + if (ast_strlen_zero(name)) { /* No name specified */ + return NULL; + } + if (find_parkinglot(name)) { /* Parkinglot with that name allready exists */ + return NULL; + } + + copylot = create_parkinglot(name); + ast_debug(1, "Building parking lot %s\n", name); + + memcpy(copylot, parkinglot, sizeof(struct ast_parkinglot)); + ast_copy_string(copylot->name, name, sizeof(copylot->name)); + AST_LIST_HEAD_INIT(©lot->parkings); + + return copylot; +} + AST_APP_OPTIONS(park_call_options, BEGIN_OPTIONS AST_APP_OPTION('r', AST_PARK_OPT_RINGING), AST_APP_OPTION('R', AST_PARK_OPT_RANDOMIZE), @@ -3719,7 +3786,7 @@ } /*! \brief Allocate parking lot structure */ -static struct ast_parkinglot *create_parkinglot(char *name) +static struct ast_parkinglot *create_parkinglot(const char *name) { struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL; @@ -3769,9 +3836,8 @@ ao2_lock(parkinglot); - if (option_debug) - ast_log(LOG_DEBUG, "Building parking lot %s\n", name); - + ast_debug(1, "Building parking lot %s\n", name); + /* Do some config stuff */ while(confvar) { if (!strcasecmp(confvar->name, "context")) { @@ -3993,6 +4059,8 @@ default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER; else if (!strcasecmp(var->value, "callee")) default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE; + } else if (!strcasecmp(var->name, "parkeddynamic")) { + parkeddynamic = ast_true(var->value); } else if (!strcasecmp(var->name, "adsipark")) { adsipark = ast_true(var->value); } else if (!strcasecmp(var->name, "transferdigittimeout")) { Index: configs/features.conf.sample =================================================================== --- configs/features.conf.sample (revision 216221) +++ configs/features.conf.sample (working copy) @@ -27,6 +27,7 @@ ; one of: callee, caller, both, no (default is no) ;parkedcallrecording = caller ; Enables or disables DTMF based one-touch recording when picking up a parked call. ; one of: callee, caller, both, no (default is no) +;parkeddynamic = no ; Enables of dynamic creation parked calls context (parkedcall section name if yes) ;adsipark = yes ; if you want ADSI parking announcements ;findslot => next ; Continue to the 'next' free parking space. ; Defaults to 'first' available