Merged revisions 286931 via svnmerge from
authorJeff Peeler <jpeeler@digium.com>
Wed, 15 Sep 2010 19:23:56 +0000 (19:23 +0000)
committerJeff Peeler <jpeeler@digium.com>
Wed, 15 Sep 2010 19:23:56 +0000 (19:23 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.8

........
  r286931 | jpeeler | 2010-09-15 14:22:15 -0500 (Wed, 15 Sep 2010) | 16 lines

  Add parking extension for non-default parking lots.

  This is a new feature that allows for parking to custom parking lots to be
  accessed directly, rather than with channel variables or by changing the
  default parking lot. The extension is set with the parkext option just as the
  default parking lot is done. Also, the manager action has been updated to
  optionally allow a specified parking lot.

  (closes issue #14882)
  Reported by: vmikhnevych
  Patches:
        patch_14882.txt uploaded by mnick (license 874)
        modified by me

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

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

CHANGES
channels/chan_dahdi.c
channels/chan_iax2.c
channels/chan_mgcp.c
channels/chan_sip.c
channels/sig_analog.c
channels/sip/include/sip.h
configs/features.conf.sample
include/asterisk/features.h
main/features.c

diff --git a/CHANGES b/CHANGES
index f942b8c..60f2978 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -436,6 +436,7 @@ Asterisk Manager Interface
    conform more closely to similar events.
  * Added a new eventfilter option per user to allow whitelisting and blacklisting
    of events.
+ * Added optional parkinglot variable for park command.
 
 Channel Event Logging
 ---------------------
@@ -1515,6 +1516,8 @@ Call Features (res_features) Changes
   * Added cli command 'features reload' to reload call features from features.conf
   * Moved into core asterisk binary.
   * Changed the default setting for featuredigittimeout to 2000 ms from 500 ms.
+  * Added the ability for custom parking lots to be configured with their own
+    parking extension with the parkext option.
 
 Language Support Changes
 ------------------------
index 7e532fc..9b1537f 100644 (file)
@@ -9739,7 +9739,7 @@ static void *analog_ss_thread(void *data)
                                tone_zone_play_tone(p->subs[idx].dfd, -1);
                        else
                                tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
-                       if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num) && strcmp(exten, ast_parking_ext())) {
+                       if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num) && !ast_parking_ext_valid(exten, chan, chan->context)) {
                                if (!res || !ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
                                        if (getforward) {
                                                /* Record this as the forwarding extension */
@@ -9875,7 +9875,7 @@ static void *analog_ss_thread(void *data)
                                getforward = 0;
                                memset(exten, 0, sizeof(exten));
                                len = 0;
-                       } else if ((p->transfer || p->canpark) && !strcmp(exten, ast_parking_ext()) &&
+                       } else if ((p->transfer || p->canpark) && ast_parking_ext_valid(exten, chan, chan->context) &&
                                                p->subs[SUB_THREEWAY].owner &&
                                                ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
                                /* This is a three way call, the main call being a real channel,
index f28bb7f..9e6d4c6 100644 (file)
@@ -9112,7 +9112,7 @@ static void dp_lookup(int callno, const char *context, const char *callednum, co
        memset(&ied1, 0, sizeof(ied1));
        mm = ast_matchmore_extension(NULL, context, callednum, 1, callerid);
        /* Must be started */
-       if (!strcmp(callednum, ast_parking_ext()) || ast_exists_extension(NULL, context, callednum, 1, callerid)) {
+       if (ast_parking_ext_valid(callednum, NULL, context) || ast_exists_extension(NULL, context, callednum, 1, callerid)) {
                dpstatus = IAX_DPSTATUS_EXISTS;
        } else if (ast_canmatch_extension(NULL, context, callednum, 1, callerid)) {
                dpstatus = IAX_DPSTATUS_CANEXIST;
@@ -9167,6 +9167,7 @@ static void spawn_dp_lookup(int callno, const char *context, const char *calledn
 struct iax_dual {
        struct ast_channel *chan1;
        struct ast_channel *chan2;
+       const char *parkexten;
 };
 
 static void *iax_park_thread(void *stuff)
@@ -9183,13 +9184,13 @@ static void *iax_park_thread(void *stuff)
        f = ast_read(chan1);
        if (f)
                ast_frfree(f);
-       res = ast_park_call(chan1, chan2, 0, &ext);
+       res = ast_park_call(chan1, chan2, 0, d->parkexten, &ext);
        ast_hangup(chan2);
        ast_log(LOG_NOTICE, "Parked on extension '%d'\n", ext);
        return NULL;
 }
 
-static int iax_park(struct ast_channel *chan1, struct ast_channel *chan2)
+static int iax_park(struct ast_channel *chan1, struct ast_channel *chan2, const char *parkexten)
 {
        struct iax_dual *d;
        struct ast_channel *chan1m, *chan2m;
@@ -9231,6 +9232,7 @@ static int iax_park(struct ast_channel *chan1, struct ast_channel *chan2)
        if ((d = ast_calloc(1, sizeof(*d)))) {
                d->chan1 = chan1m;
                d->chan2 = chan2m;
+               d->parkexten = parkexten;
                if (!ast_pthread_create_detached_background(&th, NULL, iax_park_thread, d)) {
                        return 0;
                }
@@ -10604,10 +10606,10 @@ retryowner:
                                        }
 
                                        pbx_builtin_setvar_helper(bridged_chan, "BLINDTRANSFER", iaxs[fr->callno]->owner->name);
-                                       if (!strcmp(ies.called_number, ast_parking_ext())) {
+                                       if (ast_parking_ext_valid(ies.called_number, c, iaxs[fr->callno]->context)) {
                                                struct ast_channel *saved_channel = iaxs[fr->callno]->owner;
                                                ast_mutex_unlock(&iaxsl[fr->callno]);
-                                               if (iax_park(bridged_chan, saved_channel)) {
+                                               if (iax_park(bridged_chan, saved_channel, ies.called_number)) {
                                                        ast_log(LOG_WARNING, "Failed to park call on '%s'\n", bridged_chan->name);
                                                } else {
                                                        ast_debug(1, "Parked call on '%s'\n", ast_bridged_channel(iaxs[fr->callno]->owner)->name);
index 2f953a9..499b5e5 100644 (file)
@@ -3107,7 +3107,7 @@ static void *mgcp_ss(void *data)
                        getforward = 0;
                        memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
                        len = 0;
-               } else if (!strcmp(p->dtmf_buf, ast_parking_ext()) &&
+               } else if (ast_parking_ext_valid(p->dtmf_buf, chan, chan->context) &&
                        sub->next->owner && ast_bridged_channel(sub->next->owner)) {
                        /* This is a three way call, the main call being a real channel,
                           and we're parking the first call. */
index 1cf6fe7..4157cc8 100644 (file)
@@ -1260,7 +1260,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
 static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag);
 static void check_pendings(struct sip_pvt *p);
 static void *sip_park_thread(void *stuff);
-static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno);
+static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno, char *parkexten);
 static int sip_sipredirect(struct sip_pvt *p, const char *dest);
 static int is_method_allowed(unsigned int *allowed_methods, enum sipmethod method);
 
@@ -4877,7 +4877,9 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
        ast_string_field_set(dialog, cid_name, peer->cid_name);
        ast_string_field_set(dialog, cid_tag, peer->cid_tag);
        ast_string_field_set(dialog, mwi_from, peer->mwi_from);
-       ast_string_field_set(dialog, parkinglot, peer->parkinglot);
+       if (!ast_strlen_zero(peer->parkinglot)) {
+               ast_string_field_set(dialog, parkinglot, peer->parkinglot);
+       }
        ast_string_field_set(dialog, engine, peer->engine);
        ref_proxy(dialog, obproxy_get(dialog, peer));
        dialog->callgroup = peer->callgroup;
@@ -14891,7 +14893,9 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
        ast_string_field_set(p, subscribecontext, peer->subscribecontext);
        ast_string_field_set(p, mohinterpret, peer->mohinterpret);
        ast_string_field_set(p, mohsuggest, peer->mohsuggest);
-       ast_string_field_set(p, parkinglot, peer->parkinglot);
+       if (!ast_strlen_zero(peer->parkinglot)) {
+               ast_string_field_set(p, parkinglot, peer->parkinglot);
+       }
        ast_string_field_set(p, engine, peer->engine);
        p->disallowed_methods = peer->disallowed_methods;
        set_pvt_allowed_methods(p, req);
@@ -20054,7 +20058,7 @@ static void *sip_park_thread(void *stuff)
                return NULL;
        }
 
-       res = ast_park_call(transferee, transferer, 0, &ext);
+       res = ast_park_call(transferee, transferer, 0, d->parkexten, &ext);
        
 
 #ifdef WHEN_WE_KNOW_THAT_THE_CLIENT_SUPPORTS_MESSAGE
@@ -20091,7 +20095,7 @@ static void *sip_park_thread(void *stuff)
 /*! \brief Park a call using the subsystem in res_features.c
        This is executed in a separate thread
 */
-static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno)
+static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno, char *parkexten)
 {
        struct sip_dual *d;
        struct ast_channel *transferee, *transferer;
@@ -20172,6 +20176,7 @@ static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct
                d->chan1 = transferee;  /* Transferee */
                d->chan2 = transferer;  /* Transferer */
                d->seqno = seqno;
+               d->parkexten = parkexten;
                if (ast_pthread_create_detached_background(&th, NULL, sip_park_thread, d) < 0) {
                        /* Could not start thread */
                        deinit_req(&d->req);
@@ -22064,9 +22069,8 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
                /* Fallthrough if we can't find the call leg internally */
        }
 
-
        /* Parking a call */
-       if (p->refer->localtransfer && !strcmp(p->refer->refer_to, ast_parking_ext())) {
+       if (p->refer->localtransfer && ast_parking_ext_valid(p->refer->refer_to, p->owner, p->owner->context)) {
                /* Must release c's lock now, because it will not longer be accessible after the transfer! */
                *nounlock = 1;
                ast_channel_unlock(current.chan1);
@@ -22083,7 +22087,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
                        p->refer->refer_to);
                if (sipdebug)
                        ast_debug(4, "SIP transfer to parking: trying to park %s. Parked by %s\n", current.chan2->name, current.chan1->name);
-               sip_park(current.chan2, current.chan1, req, seqno);
+               sip_park(current.chan2, current.chan1, req, seqno, p->refer->refer_to);
                return res;
        }
 
@@ -26486,6 +26490,7 @@ static int reload_config(enum channelreloadreason reason)
        ast_set_flag(&global_flags[0], SIP_DTMF_RFC2833);                       /*!< Default DTMF setting: RFC2833 */
        ast_set_flag(&global_flags[0], SIP_DIRECT_MEDIA);                       /*!< Allow re-invites */
        ast_copy_string(default_engine, DEFAULT_ENGINE, sizeof(default_engine));
+       ast_copy_string(default_parkinglot, DEFAULT_PARKINGLOT, sizeof(default_parkinglot));
 
        /* Debugging settings, always default to off */
        dumphistory = FALSE;
@@ -26994,7 +26999,9 @@ static int reload_config(enum channelreloadreason reason)
                                ast_log(LOG_WARNING, "subscribe_network_change_event value %s is not valid at line %d.\n", v->value, v->lineno);
                        }
                } else if (!strcasecmp(v->name, "snom_aoc_enabled")) {
-                               ast_set2_flag(&global_flags[2], ast_true(v->value), SIP_PAGE3_SNOM_AOC);
+                       ast_set2_flag(&global_flags[2], ast_true(v->value), SIP_PAGE3_SNOM_AOC);
+               } else if (!strcasecmp(v->name, "parkinglot")) {
+                       ast_copy_string(default_parkinglot, v->value, sizeof(default_parkinglot));
                }
        }
 
index 7bb3c29..89e4b82 100644 (file)
@@ -1939,7 +1939,7 @@ static void *__analog_ss_thread(void *data)
                        } else {
                                analog_play_tone(p, index, ANALOG_TONE_DIALTONE);
                        }
-                       if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num) && strcmp(exten, ast_parking_ext())) {
+                       if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num) && !ast_parking_ext_valid(exten, chan, chan->context)) {
                                if (!res || !ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
                                        if (getforward) {
                                                /* Record this as the forwarding extension */
@@ -2090,7 +2090,7 @@ static void *__analog_ss_thread(void *data)
                                getforward = 0;
                                memset(exten, 0, sizeof(exten));
                                len = 0;
-                       } else if ((p->transfer || p->canpark) && !strcmp(exten, ast_parking_ext()) &&
+                       } else if ((p->transfer || p->canpark) && ast_parking_ext_valid(exten, chan, chan->context) &&
                                                p->subs[ANALOG_SUB_THREEWAY].owner &&
                                                ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) {
                                /* This is a three way call, the main call being a real channel,
index 2bd1bc7..385d966 100644 (file)
@@ -768,6 +768,7 @@ struct sip_dual {
        struct ast_channel *chan2;   /*!< Second channel involved */
        struct sip_request req;      /*!< Request that caused the transfer (REFER) */
        int seqno;                   /*!< Sequence number */
+       const char *parkexten;
 };
 
 /*! \brief Parameters to the transmit_invite function */
index eb04c3c..7534d16 100644 (file)
@@ -3,7 +3,7 @@
 ;
 
 [general]
-parkext => 700                 ; What extension to dial to park        (all parking lots)
+parkext => 700                 ; What extension to dial to park
 parkpos => 701-720             ; What extensions to park calls on. (defafult parking lot)
                                ; These needs to be numeric, as Asterisk starts from the start position
                                ; and increments with one for the next parked call.
@@ -85,6 +85,7 @@ context => parkedcalls                ; Which context parked calls are in (default parking lot
 ;
 ;[parkinglot_edvina]
 ;context => edvinapark
+;parkext => 799
 ;parkpos => 800-850
 ;findslot => next
 
index c66852a..7a55ff7 100644 (file)
@@ -35,6 +35,7 @@
 #define FEATURE_MOH_LEN                80  /* same as MAX_MUSICCLASS from channel.h */
 
 #define PARK_APP_NAME "Park"
+#define DEFAULT_PARKINGLOT "default"   /*!< Default parking lot */
 
 #define AST_FEATURE_RETURN_HANGUP           -1
 #define AST_FEATURE_RETURN_SUCCESSBREAK     0
@@ -90,7 +91,7 @@ struct ast_call_feature {
  * \retval 0 on success.
  * \retval -1 on failure.
 */
-int ast_park_call(struct ast_channel *chan, struct ast_channel *host, int timeout, int *extout);
+int ast_park_call(struct ast_channel *chan, struct ast_channel *host, int timeout, const char *parkexten, int *extout);
 
 /*! 
  * \brief Park a call via a masqueraded channel
@@ -106,10 +107,11 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *host, int timeou
 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *host, int timeout, int *extout);
 
 /*! 
- * \brief Determine system parking extension
- * \returns the call parking extension for drivers that provide special call parking help 
+ * \brief Determine if parking extension exists in a given context
+ * \retval 0 if extension does not exist
+ * \retval 1 if extension does exist
 */
-const char *ast_parking_ext(void);
+int ast_parking_ext_valid(const char *exten_str, struct ast_channel *chan, const char *context);
 
 /*! \brief Determine system call pickup extension */
 const char *ast_pickup_ext(void);
index 68d843b..bd8cb4c 100644 (file)
@@ -257,6 +257,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <parameter name="Timeout">
                                <para>Number of milliseconds to wait before callback.</para>
                        </parameter>
+                       <parameter name="Parkinglot">
+                               <para>Parking lot to park channel in.</para>
+                       </parameter>
                </syntax>
                <description>
                        <para>Park a channel.</para>
@@ -289,10 +292,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  ***/
 
 #define DEFAULT_PARK_TIME 45000
+#define DEFAULT_PARK_EXTENSION "700"
 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 1000
 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
-#define DEFAULT_PARKINGLOT "default"                   /*!< Default parking lot */
 #define DEFAULT_ATXFER_DROP_CALL 0
 #define DEFAULT_ATXFER_LOOP_DELAY 10000
 #define DEFAULT_ATXFER_CALLBACK_RETRIES 2
@@ -345,6 +348,7 @@ struct parkeduser {
 /*! \brief Structure for parking lots which are put in a container. */
 struct ast_parkinglot {
        char name[AST_MAX_CONTEXT];
+       char parkext[AST_MAX_EXTENSION];                                /*!< Parkingextension */
        char parking_con[AST_MAX_EXTENSION];            /*!< Context for which parking is made accessible */
        char parking_con_dial[AST_MAX_EXTENSION];       /*!< Context for dialback for parking (KLUDGE) */
        int parking_start;                              /*!< First available extension for parking */
@@ -358,6 +362,7 @@ struct ast_parkinglot {
        int parkedcallreparking;                        /*!< Enable DTMF based parking on bridge when picking up parked calls */
        int parkedcallhangup;                           /*!< Enable DTMF based hangup on a bridge when pickup up parked calls */
        int parkedcallrecording;                        /*!< Enable DTMF based recording on a bridge when picking up parked calls */
+       unsigned short the_mark:1;                      /*!< Used during reloads, that which bears the_mark shall be deleted! */
        AST_LIST_HEAD(parkinglot_parklist, parkeduser) parkings; /*!< List of active parkings in this parkinglot */
 };
 
@@ -443,9 +448,47 @@ 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)
+static int find_parkinglot_by_position_cb(void *obj, void *args, int flags)
+{
+       struct ast_parkinglot *parkinglot = obj;
+       int *parkpos = args;
+
+       if (*parkpos >= parkinglot->parking_start && *parkpos <= parkinglot->parking_stop) {
+               return CMP_MATCH | CMP_STOP;
+       }
+
+       return 0;
+}
+
+static int find_parkinglot_by_exten_cb(void *obj, void *args, int flags)
 {
-       return parking_ext;
+       struct ast_parkinglot *parkinglot = obj;
+       const char *parkext = args;
+
+       if (!strcmp(parkinglot->parkext, parkext)) {
+               return CMP_MATCH | CMP_STOP;
+       }
+
+       return 0;
+}
+
+int ast_parking_ext_valid(const char *exten_str, struct ast_channel *chan, const char *context)
+{
+       struct ast_exten *exten;
+       struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
+       const char *app_at_exten;
+
+       exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL, E_MATCH);
+       if (!exten) {
+               return 0;
+       }
+
+       app_at_exten = ast_get_extension_app(exten);
+       if (!app_at_exten || strcmp(PARK_APP_NAME, app_at_exten)) {
+               return 0;
+       }
+
+       return 1;
 }
 
 const char *ast_pickup_ext(void)
@@ -692,6 +735,7 @@ struct ast_park_call_args {
        uint32_t flags;
        /*! Parked user that has already obtained a parking space */
        struct parkeduser *pu;
+       struct ast_parkinglot *parkinglot; /*! parkinglot to be parked in, based on parkext */
 };
 
 static struct parkeduser *park_space_reserve(struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
@@ -700,17 +744,25 @@ static struct parkeduser *park_space_reserve(struct ast_channel *chan, struct as
        int i, parking_space = -1, parking_range;
        const char *parkinglotname = NULL;
        const char *parkingexten;
-       struct ast_parkinglot *parkinglot = NULL;
+       struct ast_parkinglot *parkinglot;
 
-       if (peer)
+       if (args->parkinglot) {
+               parkinglot = args->parkinglot;
+               parkinglotname = parkinglot->name;
+       } else if (peer) {
                parkinglotname = findparkinglotname(peer);
-       else /* peer was NULL, check chan (ParkAndAnnounce / res_agi) */
+       } else { /* peer was NULL, check chan (ParkAndAnnounce / res_agi) */
                parkinglotname = findparkinglotname(chan);
+       }
 
-       if (parkinglotname) {
-               ast_debug(1, "Found chanvar Parkinglot: %s\n", parkinglotname);
-               parkinglot = find_parkinglot(parkinglotname);
-
+       if (!args->parkinglot) {
+               if (parkinglotname) {
+                       parkinglot = find_parkinglot(parkinglotname);
+               } else {
+                       ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n");
+                       parkinglot = parkinglot_addref(default_parkinglot);
+               }
+               ast_debug(1, "Found chanvar Parkinglot: %s\n", parkinglot->name);
        }
 
        /* Dynamically create parkinglot */
@@ -761,8 +813,7 @@ static struct parkeduser *park_space_reserve(struct ast_channel *chan, struct as
                parkinglot = parkinglot_addref(default_parkinglot);
        }
 
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Parkinglot: %s\n", parkinglot->name);
+       ast_debug(1, "Parkinglot: %s\n", parkinglot->name);
 
        /* Allocate memory for parking data */
        if (!(pu = ast_calloc(1, sizeof(*pu)))) {
@@ -844,9 +895,8 @@ static struct parkeduser *park_space_reserve(struct ast_channel *chan, struct as
 
        pu->notquiteyet = 1;
        pu->parkingnum = parking_space;
-       pu->parkinglot = parkinglot_addref(parkinglot);
+       pu->parkinglot = parkinglot;
        AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list);
-       parkinglot_unref(parkinglot);
 
        return pu;
 }
@@ -1001,21 +1051,27 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, st
 }
 
 /*! \brief Park a call */
-int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
+int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, const char *parkexten, int *extout)
 {
+       struct ast_parkinglot *found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, (void *) parkexten);
+
        struct ast_park_call_args args = {
                .timeout = timeout,
                .extout = extout,
+               .parkinglot = found_lot,
        };
 
        return park_call_full(chan, peer, &args);
 }
 
+/*!
+ * \param rchan is the transferee
+ * \param peer is the transferer
+ */
 static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, struct ast_park_call_args *args)
 {
        struct ast_channel *chan;
        struct ast_frame *f;
-       int park_status;
        struct ast_park_call_args park_args = {0,};
 
        if (!args) {
@@ -1025,8 +1081,9 @@ static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, i
        }
 
        if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) {
-               if (peer)
-                       ast_stream_and_wait(peer, "beeperr", "");
+               if (peer) {
+                       ast_stream_and_wait(peer, "pbx-parkingfailed", "");
+               }
                return AST_FEATURE_RETURN_PARKFAILED;
        }
 
@@ -1061,12 +1118,8 @@ static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, i
                args->orig_chan_name = ast_strdupa(peer->name);
        }
 
-       park_status = park_call_full(chan, peer, args);
-       if (park_status == 1) {
-       /* would be nice to play "invalid parking extension" */
-               ast_hangup(chan);
-               return -1;
-       }
+       /* parking space reserved, return code check unnecessary */
+       park_call_full(chan, peer, args);
 
        return 0;
 }
@@ -1077,16 +1130,11 @@ int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int
        return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
 }
 
-static int masq_park_call_announce_args(struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
+static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
 {
        return masq_park_call(rchan, peer, 0, NULL, 1, args);
 }
 
-static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
-{
-       return masq_park_call(rchan, peer, timeout, extout, 1, NULL);
-}
-
 #ifdef TEST_FRAMEWORK
 static int fake_fixup(struct ast_channel *clonechan, struct ast_channel *original)
 {
@@ -1273,25 +1321,14 @@ static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
        }
 }
 
-/*! 
- * \brief support routing for one touch call parking
- * \param chan channel parking call
- * \param peer channel to be parked
- * \param config unsed
- * \param code unused
- * \param sense feature options
- *
- * \param data
- * Setup channel, set return exten,priority to 's,1'
- * answer chan, sleep chan, park call
-*/
-static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+static int parkcall_helper(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, struct ast_park_call_args *args)
 {
-       struct ast_channel *parker;
-       struct ast_channel *parkee;
        int res = 0;
 
-       set_peers(&parker, &parkee, peer, chan, sense);
+       if (args) {
+               ast_debug(1, "Parkinglot specified for builtin_parkcall: %s\n", args->parkinglot->name);
+       }
+
        /* we used to set chan's exten and priority to "s" and 1
           here, but this generates (in some cases) an invalid
           extension, and if "s" exists, could errantly
@@ -1306,13 +1343,33 @@ static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer,
                res = ast_safe_sleep(chan, 1000);
 
        if (!res) { /* one direction used to call park_call.... */
-               res = masq_park_call_announce(parkee, parker, 0, NULL);
+               struct ast_channel *parker;
+               struct ast_channel *parkee;
+               set_peers(&parker, &parkee, peer, chan, sense);
+               res = masq_park_call_announce(parkee, parker, args);
                /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
        }
 
        return res;
 }
 
+/*! 
+ * \brief support routing for one touch call parking
+ * \param chan channel parking call
+ * \param peer channel to be parked
+ * \param config unsed
+ * \param code unused
+ * \param sense feature options
+ *
+ * \param data
+ * Setup channel, set return exten,priority to 's,1'
+ * answer chan, sleep chan, park call
+*/
+static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+{
+       return parkcall_helper(chan, peer, config, code, sense, NULL);
+}
+
 /*! \brief Play message to both caller and callee in bridged call, plays synchronously, autoservicing the
        other channel during the message, so please don't use this for very long messages
  */
@@ -1620,6 +1677,7 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
        struct ast_channel *transferer;
        struct ast_channel *transferee;
        const char *transferer_real_context;
+       struct ast_parkinglot *found_lot = NULL;
        char xferto[256];
        int res, parkstatus = 0;
 
@@ -1647,11 +1705,16 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
                finishup(transferee);
                return res;
        }
-       if (!strcmp(xferto, ast_parking_ext())) {
+
+       found_lot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &xferto);
+       if (found_lot) {
+               struct ast_park_call_args args = {
+                       .parkinglot = found_lot,
+               };
                res = finishup(transferee);
                if (res)
                        res = -1;
-               else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL))) {    /* success */
+               else if (!(parkstatus = masq_park_call_announce(transferee, transferer, &args))) {      /* success */
                        /* We return non-zero, but tell the PBX not to hang the channel when
                           the thread dies -- We have to be careful now though.  We are responsible for 
                           hanging up the channel, else it will never be hung up! */
@@ -1706,7 +1769,7 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
        } else {
                ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
        }
-       if (parkstatus != AST_FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) {
+       if (parkstatus != AST_FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) { /* Play 'extension does not exist' */
                finishup(transferee);
                return -1;
        }
@@ -1769,6 +1832,7 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
        struct ast_party_connected_line connected_line;
        struct ast_datastore *features_datastore;
        struct ast_dial_features *dialfeatures = NULL;
+       struct ast_parkinglot *parkinglot;
 
        ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
        set_peers(&transferer, &transferee, peer, chan, sense);
@@ -1811,12 +1875,16 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
                return AST_FEATURE_RETURN_SUCCESS;
        }
 
-       /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of
-        * the different variables for handling this properly with a builtin_atxfer */
-       if (!strcmp(xferto, ast_parking_ext())) {
-               finishup(transferee);
-               return builtin_parkcall(chan, peer, config, code, sense, data);
-       }
+       /* If we are attended transfering to parking, just use parkcall_helper instead of trying to track all of
+        * the different variables for handling this properly with a builtin_atxfer */
+       parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &xferto);
+       if (parkinglot) {
+               struct ast_park_call_args args = {
+                       .parkinglot = parkinglot,
+               };
+               finishup(transferee);
+               return parkcall_helper(chan, peer, config, code, sense, &args);
+       }
 
        l = strlen(xferto);
        snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);     /* append context */
@@ -3762,6 +3830,7 @@ int manage_parkinglot(struct ast_parkinglot *curlot, const struct pollfd *pfds,
                                        } else
                                                ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name);
                                        AST_LIST_REMOVE_CURRENT(list);
+                                       parkinglot_unref(pu->parkinglot);
                                        free(pu);
                                        break;
                                } else {
@@ -3847,18 +3916,16 @@ static void *do_parking_thread(void *ignore)
 /*! \brief Find parkinglot by name */
 struct ast_parkinglot *find_parkinglot(const char *name)
 {
-       struct ast_parkinglot *parkinglot = NULL;
-       struct ast_parkinglot tmp_parkinglot;
-       
-       if (ast_strlen_zero(name))
-               return NULL;
-
-       ast_copy_string(tmp_parkinglot.name, name, sizeof(tmp_parkinglot.name));
+       struct ast_parkinglot *parkinglot;
 
-       parkinglot = ao2_find(parkinglots, &tmp_parkinglot, OBJ_POINTER);
+       if (ast_strlen_zero(name)) {
+               return NULL;
+       }
 
-       if (parkinglot && option_debug)
-               ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name);
+       parkinglot = ao2_find(parkinglots, (void *) name, 0);
+       if (parkinglot) {
+               ast_debug(1, "Found Parkinglot: %s\n", parkinglot->name);
+       }
 
        return parkinglot;
 }
@@ -3870,7 +3937,10 @@ struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkin
        if (ast_strlen_zero(name)) { /* No name specified */
                return NULL;
        }
-       if (find_parkinglot(name)) { /* Parkinglot with that name allready exists */
+       if ((copylot = find_parkinglot(name))) { /* Parkinglot with that name already exists */
+               if (copylot) {
+                       ao2_ref(copylot, -1);
+               }
                return NULL;
        }
 
@@ -3962,7 +4032,8 @@ static int park_call_exec(struct ast_channel *chan, const char *data)
                ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
                args.flags = flags.flags;
 
-               res = masq_park_call_announce_args(chan, chan, &args);
+               args.parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_exten_cb, &orig_exten);
+               res = masq_park_call_announce(chan, chan, &args);
                /* Continue on in the dialplan */
                if (res == 1) {
                        ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
@@ -3977,7 +4048,7 @@ static int park_call_exec(struct ast_channel *chan, const char *data)
 }
 
 /*! \brief Pickup parked call */
-static int park_exec_full(struct ast_channel *chan, const char *data, struct ast_parkinglot *parkinglot)
+static int park_exec_full(struct ast_channel *chan, const char *data)
 {
        int res = 0;
        struct ast_channel *peer=NULL;
@@ -3985,11 +4056,13 @@ static int park_exec_full(struct ast_channel *chan, const char *data, struct ast
        struct ast_context *con;
        int park = 0;
        struct ast_bridge_config config;
+       struct ast_parkinglot *parkinglot;
 
-       if (data)
+       if (data) {
                park = atoi((char *) data);
+       }
 
-       parkinglot = find_parkinglot(findparkinglotname(chan));         
+       parkinglot = ao2_callback(parkinglots, 0, find_parkinglot_by_position_cb, (void *) &park);
        if (!parkinglot)
                parkinglot = default_parkinglot;
 
@@ -4126,6 +4199,7 @@ static int park_exec_full(struct ast_channel *chan, const char *data, struct ast
                        ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
                }
 
+               parkinglot_unref(parkinglot);
                res = ast_bridge_call(chan, peer, &config);
 
                pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
@@ -4147,7 +4221,7 @@ static int park_exec_full(struct ast_channel *chan, const char *data, struct ast
 
 static int park_exec(struct ast_channel *chan, const char *data) 
 {
-       return park_exec_full(chan, data, default_parkinglot);
+       return park_exec_full(chan, data);
 }
 
 /*! \brief Unreference parkinglot object. If no more references,
@@ -4155,15 +4229,13 @@ static int park_exec(struct ast_channel *chan, const char *data)
 static void parkinglot_unref(struct ast_parkinglot *parkinglot) 
 {
        int refcount = ao2_ref(parkinglot, -1);
-       if (option_debug > 2)
-               ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1);
+       ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1);
 }
 
 static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot)
 {
        int refcount = ao2_ref(parkinglot, +1);
-       if (option_debug > 2)
-               ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
+       ast_debug(3, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
        return parkinglot;
 }
 
@@ -4193,10 +4265,28 @@ static void parkinglot_destroy(void *obj)
        con = ast_context_find(ruin->parking_con);
        if (con)
                ast_context_destroy(con, registrar);
-       ao2_unlink(parkinglots, ruin);
 }
 
-/*! \brief Build parkinglot from configuration and chain it in */
+/*! 
+ * \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);
+       }
+}
+
+/*! \brief Build parkinglot from configuration and chain it in if it doesn't already exist */
 static struct ast_parkinglot *build_parkinglot(char *name, struct ast_variable *var)
 {
        struct ast_parkinglot *parkinglot;
@@ -4224,6 +4314,8 @@ static struct ast_parkinglot *build_parkinglot(char *name, struct ast_variable *
        while(confvar) {
                if (!strcasecmp(confvar->name, "context")) {
                        ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con));
+               } else if (!strcasecmp(confvar->name, "parkext")) {
+                       ast_copy_string(parkinglot->parkext, confvar->value, sizeof(parkinglot->parkext));
                } else if (!strcasecmp(confvar->name, "parkingtime")) {
                        if ((sscanf(confvar->value, "%30d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) {
                                ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", confvar->value);
@@ -4283,6 +4375,10 @@ static struct ast_parkinglot *build_parkinglot(char *name, struct ast_variable *
        if (parkinglot->parkingtime == 0) {
                parkinglot->parkingtime = DEFAULT_PARK_TIME;
        }
+       if (ast_strlen_zero(parkinglot->parkext)) {
+               ast_debug(2, "no parkext specified for %s - setting it to %s\n", parkinglot->name, DEFAULT_PARK_EXTENSION);
+               ast_copy_string(parkinglot->parkext, DEFAULT_PARK_EXTENSION, sizeof(parkinglot->parkext));
+       }
 
        if (!var) {     /* Default parking lot */
                ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con));
@@ -4304,22 +4400,26 @@ static struct ast_parkinglot *build_parkinglot(char *name, struct ast_variable *
 
        /* Add a parking extension into the context */
        if (!error && !oldparkinglot) {
-               if (!ast_strlen_zero(ast_parking_ext())) {
-                       if (ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1)
+               if (!ast_strlen_zero(parkinglot->parkext)) {
+                       if (ast_add_extension2(con, 1, parkinglot->parkext, 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1)
                                error = 1;
                }
        }
 
+       /* Add parking hints */
+       if (parkinglot->parkaddhints)
+               park_add_hints(parkinglot->parking_con, parkinglot->parking_start, parkinglot->parking_stop);
+
        ao2_unlock(parkinglot);
 
        if (error) {
                ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name);
                parkinglot_destroy(parkinglot);
+               parkinglot_unref(parkinglot);
                return NULL;
        }
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end);
-
+       ast_debug(1, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end);
+       parkinglot->the_mark = 0;
 
        /* Move it into the list, if it wasn't already there */
        if (!oldparkinglot) {
@@ -4330,26 +4430,6 @@ static struct ast_parkinglot *build_parkinglot(char *name, struct ast_variable *
        return parkinglot;
 }
 
-
-/*! 
- * \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;
@@ -4360,8 +4440,6 @@ static int load_config(void)
        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 * const categories[] = { 
                /* Categories in features.conf that are not
@@ -4372,32 +4450,27 @@ static int load_config(void)
                "applicationmap"
        };
 
+       default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
        if (default_parkinglot) {
-               strcpy(old_parking_con, default_parkinglot->parking_con);
-               strcpy(old_parking_ext, parking_ext);
-       } else {
-               default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
-               if (default_parkinglot) {
-                       ao2_lock(default_parkinglot);
-                       default_parkinglot->parking_start = 701;
-                       default_parkinglot->parking_stop = 750;
-                       default_parkinglot->parking_offset = 0;
-                       default_parkinglot->parkfindnext = 0;
-                       default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
-                       ao2_unlock(default_parkinglot);
-               }
+               ao2_lock(default_parkinglot);
+               ast_copy_string(default_parkinglot->parkext, DEFAULT_PARK_EXTENSION, sizeof(default_parkinglot->parkext));
+               default_parkinglot->parking_start = 701;
+               default_parkinglot->parking_stop = 750;
+               default_parkinglot->parking_offset = 0;
+               default_parkinglot->parkfindnext = 0;
+               default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
+               ao2_unlock(default_parkinglot);
        }
+       
        if (default_parkinglot) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Configuration of default parkinglot done.\n");
+               ast_debug(1, "Configuration of default parkinglot done.\n");
        } else {
                ast_log(LOG_ERROR, "Configuration of default parkinglot failed.\n");
                return -1;
        }
-       
 
        /* Reset to defaults */
-       strcpy(parking_ext, "700");
+       strcpy(default_parkinglot->parkext, DEFAULT_PARK_EXTENSION);
        strcpy(pickup_ext, "*8");
        courtesytone[0] = '\0';
        strcpy(xfersound, "beep");
@@ -4428,7 +4501,7 @@ static int load_config(void)
        }
        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));
+                       ast_copy_string(default_parkinglot->parkext, var->value, sizeof(default_parkinglot->parkext));
                } else if (!strcasecmp(var->name, "context")) {
                        ast_copy_string(default_parkinglot->parking_con, var->value, sizeof(default_parkinglot->parking_con));
                } else if (!strcasecmp(var->name, "parkingtime")) {
@@ -4682,22 +4755,15 @@ static int load_config(void)
 
        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, 0))
-                               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_or_create(NULL, NULL, default_parkinglot->parking_con, registrar))) {
                ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", default_parkinglot->parking_con);
                return -1;
        }
-       res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
+       res = ast_add_extension2(con, 1, default_parkinglot->parkext, 1, NULL, NULL, parkcall, NULL, NULL, registrar);
        if (default_parkinglot->parkaddhints)
                park_add_hints(default_parkinglot->parking_con, default_parkinglot->parking_start, default_parkinglot->parking_stop);
        if (!res)
-               notify_metermaids(ast_parking_ext(), default_parkinglot->parking_con, AST_DEVICE_INUSE);
+               notify_metermaids(default_parkinglot->parkext, default_parkinglot->parking_con, AST_DEVICE_INUSE); 
        return res;
 
 }
@@ -4776,9 +4842,11 @@ static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cl
        while ((curlot = ao2_iterator_next(&iter))) {
                ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
                ast_cli(a->fd, "------------\n");
-               ast_cli(a->fd,"%-22s:      %s\n", "Parking extension", parking_ext);
+               ast_cli(a->fd,"%-22s:      %s\n", "Parking extension", curlot->parkext);
                ast_cli(a->fd,"%-22s:      %s\n", "Parking context", curlot->parking_con);
                ast_cli(a->fd,"%-22s:      %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop);
+               ast_cli(a->fd,"%-22s:      %d\n", "Parkingtime", curlot->parkingtime);
+               ast_cli(a->fd,"%-22s:      %s\n", "MusicOnHold class", curlot->mohclass);
                ast_cli(a->fd,"\n");
                ao2_ref(curlot, -1);
        }
@@ -4787,17 +4855,27 @@ static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cl
        return CLI_SUCCESS;
 }
 
+static int parkinglot_markall_cb(void *obj, void *arg, int flags)
+{
+       struct ast_parkinglot *parkinglot = obj;
+       parkinglot->the_mark = 1;
+       return 0;
+}
+
+static int parkinglot_is_marked_cb(void *obj, void *arg, int flags)
+{
+       struct ast_parkinglot *parkinglot = obj;
+       return parkinglot->the_mark ? CMP_MATCH : 0;
+}
+
 int ast_features_reload(void)
 {
        int res;
-       /* Release parking lot list */
-       //ASTOBJ_CONTAINER_MARKALL(&parkinglots);
-       // TODO: I don't think any marking is necessary
 
-       /* Reload configuration */
-       res = load_config();
+       ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL, "callback to mark all parkinglots");
+       res = load_config(); /* Reload configuration */
+       ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL, "callback to remove all marked parkinglots");
        
-       //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
        return res;
 }
 
@@ -5010,7 +5088,8 @@ static char *handle_parkedcalls(struct ast_cli_entry *e, int cmd, struct ast_cli
        iter = ao2_iterator_init(parkinglots, 0);
        while ((curlot = ao2_iterator_next(&iter))) {
                int lotparked = 0;
-               ast_cli(a->fd, "*** Parking lot: %s\n", curlot->name);
+               /* subtract ref for iterator and for configured parking lot */
+               ast_cli(a->fd, "*** Parking lot: %s (%d)\n", curlot->name, ao2_ref(curlot, 0) - 2);
 
                AST_LIST_LOCK(&curlot->parkings);
                AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
@@ -5106,11 +5185,11 @@ static int manager_park(struct mansession *s, const struct message *m)
        const char *channel = astman_get_header(m, "Channel");
        const char *channel2 = astman_get_header(m, "Channel2");
        const char *timeout = astman_get_header(m, "Timeout");
+       const char *parkinglotname = astman_get_header(m, "Parkinglot");
        char buf[BUFSIZ];
-       int to = 0;
        int res = 0;
-       int parkExt = 0;
        struct ast_channel *ch1, *ch2;
+       struct ast_park_call_args args = {0,};
 
        if (ast_strlen_zero(channel)) {
                astman_send_error(s, m, "Channel not specified");
@@ -5135,16 +5214,19 @@ static int manager_park(struct mansession *s, const struct message *m)
                return 0;
        }
 
+       if (!ast_strlen_zero(timeout)) {
+               sscanf(timeout, "%30d", &args.timeout);
+       }
+       if (!ast_strlen_zero(parkinglotname)) {
+               args.parkinglot = find_parkinglot(parkinglotname);
+       }
+
        ast_channel_lock(ch1);
        while (ast_channel_trylock(ch2)) {
                CHANNEL_DEADLOCK_AVOIDANCE(ch1);
        }
 
-       if (!ast_strlen_zero(timeout)) {
-               sscanf(timeout, "%30d", &to);
-       }
-
-       res = ast_masq_park_call(ch1, ch2, to, &parkExt);
+       res = masq_park_call(ch1, ch2, 0, NULL, 0, &args);
        if (!res) {
                ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
                astman_send_ack(s, m, "Park successful");