addition of dynamic parkinglots feature
authorDavid Vossel <dvossel@digium.com>
Wed, 17 Feb 2010 18:29:48 +0000 (18:29 +0000)
committerDavid Vossel <dvossel@digium.com>
Wed, 17 Feb 2010 18:29:48 +0000 (18:29 +0000)
This feature allows for parkinglots to be created dynamically within
the dialplan.  Thanks to all who were involved with getting this patch
written and tested!

(closes issue #15135)
Reported by: IgorG
Patches:
      features.dynamic_park.v3.diff uploaded by IgorG (license 20)
      2009090400_dynamicpark.diff.txt uploaded by mvanbaak (license 7)
      dynamic_parkinglot.diff uploaded by dvossel (license 671)
Tested by: eliel, IgorG, acunningham, mvanbaak, zktech

Review: https://reviewboard.asterisk.org/r/352/

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@247248 65c4cc65-6c06-0410-ace0-fbb531ad65f3

CHANGES
configs/features.conf.sample
main/features.c

diff --git a/CHANGES b/CHANGES
index 132d31e..a2b6c56 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -197,6 +197,15 @@ Dialplan Variables
  * Added DYNAMIC_FEATURENAME which holds the last triggered dynamic feature.
  * Added DYNAMIC_PEERNAME which holds the unique channel name on the other side
    and is set when a dynamic feature is triggered.
+ * Added PARKINGLOT which can be used with parkeddynamic feature.conf option
+   to dynamically create a new parking lot matching the value this varible is
+   set to.
+ * Added PARKINGDYNAMIC which represents the template parkinglot defined in
+   features.conf that should be the base for dynamic parkinglots.
+ * Added PARKINGDYNCONTEXT which tells what context a newly created dynamic
+   parkinglot should have.
+ * Added PARKINGDYNPOS which holds what parking positions a dynamic parkinglot
+   should have.
 
 Queue changes
 -------------
@@ -396,6 +405,8 @@ Miscellaneous
  * jabber.conf supports a new option auth_policy that toggles auto user registration.
  * A new lockconfdir option has been added to asterisk.conf to protect the
    configuration directory (/etc/asterisk by default) during reloads.
+ * The parkeddynamic option has been added to features.conf to enable the creation
+   of dynamic parkinglots.
 
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 1.6.1 to Asterisk 1.6.2  -------------
index 23732d8..6e582f7 100644 (file)
@@ -27,6 +27,7 @@ context => parkedcalls                ; Which context parked calls are in (default parking lot
                                 ; 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 = yes            ; Enables dynamically created parkinglots. (default is no)
 ;adsipark = yes                        ; if you want ADSI parking announcements
 ;findslot => next              ; Continue to the 'next' free parking space.
                                ; Defaults to 'first' available
index 329dd17..9c0768f 100644 (file)
@@ -212,6 +212,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <para>If you set the <variable>PARKINGEXTEN</variable> 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.</para>
+                       <para>If you set the <variable>PARKINGLOT</variable> variable, Park() will park the call
+                       in that parkinglot.</para>
+                       <para>If you set the <variable>PARKINGDYNAMIC</variable> variable, this parkinglot from features.conf
+                       will be used as template for the newly created dynamic lot.</para>
+                       <para>If you set the <variable>PARKINGDYNCONTEXT</variable> variable the newly created dynamic
+                       parking lot will use this context.</para>
+                       <para>If you set the <variable>PARKINGDYNPOS</variable> variable the newly created dynamic parkinglot
+                       will use those parking postitions.</para>
                </description>
                <see-also>
                        <ref type="application">ParkAndAnnounce</ref>
@@ -356,6 +364,7 @@ char parking_ext[AST_MAX_EXTENSION];            /*!< Extension you type to park
 
 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 */
@@ -426,7 +435,8 @@ static void parkinglot_unref(struct ast_parkinglot *parkinglot);
 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)
 {
@@ -679,23 +689,67 @@ struct ast_park_call_args {
        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);
+
        }
+
+       /* Dynamically create parkinglot */
+       if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) {
+               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 = parkinglot_addref(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_copy) {
+                       /* unref our tempory copy */
+                       parkinglot_unref(parkinglot_copy);
+                       parkinglot_copy = NULL;
+               }
+       }
+
        if (!parkinglot) {
                parkinglot = parkinglot_addref(default_parkinglot);
        }
@@ -3508,6 +3562,27 @@ struct ast_parkinglot *find_parkinglot(const char *name)
        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(&copylot->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),
@@ -3792,7 +3867,7 @@ static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglo
 }
 
 /*! \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;
 
@@ -3842,9 +3917,8 @@ static struct ast_parkinglot *build_parkinglot(char *name, struct ast_variable *
 
        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")) {
@@ -4027,6 +4101,7 @@ static int load_config(void)
        pickupfailsound[0] = '\0';
        adsipark = 0;
        comebacktoorigin = 1;
+       parkeddynamic = 0;
 
        default_parkinglot->parkaddhints = 0;
        default_parkinglot->parkedcalltransfers = 0;
@@ -4098,6 +4173,8 @@ static int load_config(void)
                                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")) {