diff --git a/apps/app_disa.c b/apps/app_disa.c
index a2e738ab7694d68757d1b44849c6c1a6f04497d4..372bcca7a074e92760959566bff2c99fd6f3d572 100755
--- a/apps/app_disa.c
+++ b/apps/app_disa.c
@@ -330,7 +330,7 @@ static int disa_exec(struct ast_channel *chan, void *data)
 		strncpy(chan->context, ourcontext, sizeof(chan->context) - 1);
 		strncpy(chan->accountcode, acctcode, sizeof(chan->accountcode) - 1);
 		chan->priority = 0;
-		ast_cdr_init(chan->cdr,chan);
+		ast_cdr_reset(chan->cdr,AST_CDR_FLAG_POSTED);
 		LOCAL_USER_REMOVE(u);
 		return 0;
 	}
diff --git a/channels/chan_agent.c b/channels/chan_agent.c
index 526f24e121d9c8f45c521017d641e32be3c0be1b..9dc0ce7a6d954ab81eab294eee33fe4eafd0b69f 100755
--- a/channels/chan_agent.c
+++ b/channels/chan_agent.c
@@ -1366,9 +1366,14 @@ static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
 					exten = NULL;
 			}
 		}
-		if ( options ) {
+		if (options) {
 			while (*options) {
 				option = (char)options[0];
+				if ((option >= 0) && (option <= '9'))
+				{
+					options++;
+					continue;
+				}
 				if (option=='s')
 					play_announcement = 0;
 				else {
diff --git a/channels/chan_zap.c b/channels/chan_zap.c
index 9f6475e8a315d9af094c44dd9365ef455ecc075a..76a8c0f7bcdfb469646cd9c9053ce547a50fbbb7 100755
--- a/channels/chan_zap.c
+++ b/channels/chan_zap.c
@@ -196,6 +196,8 @@ static int threewaycalling = 0;
 
 static int transfer = 0;
 
+static int canpark = 0;
+
 static int cancallforward = 0;
 
 static float rxgain = 0.0;
@@ -521,6 +523,7 @@ static struct zt_pvt {
 	int callwaitingcallerid;
 	int threewaycalling;
 	int transfer;
+	int canpark;
 	int digital;
 	int outgoing;
 	int dnd;
@@ -5129,7 +5132,7 @@ static void *ss_thread(void *data)
 				getforward = 0;
 				memset(exten, 0, sizeof(exten));
 				len = 0;
-			} else if (p->transfer && !strcmp(exten, ast_parking_ext()) && 
+			} else if ((p->transfer || p->canpark) && !strcmp(exten, ast_parking_ext()) && 
 						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, 
@@ -6596,6 +6599,7 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
 			tmp->confno = -1;
 			tmp->propconfno = -1;
 		}
+		tmp->canpark = canpark;
 		tmp->transfer = transfer;
 		strncpy(tmp->defcontext,context,sizeof(tmp->defcontext)-1);
 		strncpy(tmp->language, language, sizeof(tmp->language)-1);
@@ -9333,6 +9337,8 @@ static int setup_zap(int reload)
 			adsi = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "transfer")) {
 			transfer = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "canpark")) {
+			canpark = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "echocancelwhenbridged")) {
 			echocanbridged = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "busydetect")) {
diff --git a/configs/zapata.conf.sample b/configs/zapata.conf.sample
index 5e87cd76b346f6c520821e9f84aa21d27fea5951..c046dedc062f43839d3eeee3237ce2c5cf8a7499 100755
--- a/configs/zapata.conf.sample
+++ b/configs/zapata.conf.sample
@@ -193,9 +193,15 @@ callwaitingcallerid=yes
 threewaycalling=yes
 ;
 ; Support flash-hook call transfer (requires three way calling)
+; Also enables call parking (overrides the 'canpark' parameter)
 ;
 transfer=yes
 ;
+; Allow call parking
+; ('canpark=no' is overridden by 'transfer=yes')
+;
+canpark=yes
+;
 ; Support call forward variable
 ;
 cancallforward=yes
diff --git a/res/res_features.c b/res/res_features.c
index 1010740c9e880769eff1989486e4d06c7454c9e4..548a8744ce2bbd936441ddc3ade88d5bd4633741 100755
--- a/res/res_features.c
+++ b/res/res_features.c
@@ -28,6 +28,7 @@
 #include <asterisk/manager.h>
 #include <asterisk/utils.h>
 #include <asterisk/adsi.h>
+#include <pthread.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <unistd.h>
@@ -49,6 +50,9 @@ static int parkingtime = DEFAULT_PARK_TIME;
 /* Context for which parking is made accessible */
 static char parking_con[AST_MAX_EXTENSION] = "parkedcalls";
 
+/* Context for dialback for parking (KLUDGE) */
+static char parking_con_dial[AST_MAX_EXTENSION] = "park-dial";
+
 /* Extension you type to park the call */
 static char parking_ext[AST_MAX_EXTENSION] = "700";
 
@@ -103,6 +107,7 @@ struct parkeduser {
 	int priority;
 	int parkingtime;
 	int notquiteyet;
+	char peername[1024];
 	struct parkeduser *next;
 };
 
@@ -152,6 +157,7 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
 	struct ast_context *con;
 	pu = malloc(sizeof(struct parkeduser));
 	if (pu) {
+		memset(pu,0,sizeof(struct parkeduser));
 		ast_mutex_lock(&parking_lock);
 		for (x=parking_start;x<=parking_stop;x++) {
 			cur = parkinglot;
@@ -179,6 +185,10 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
 				pu->parkingtime = parkingtime;
 			if (extout)
 				*extout = x;
+			if (peer)
+			{
+				strncpy(pu->peername,peer->name,sizeof(pu->peername) - 1);
+			}
 			/* Remember what had been dialed, so that if the parking
 			   expires, we try to come back to the same place */
 			if (!ast_strlen_zero(chan->macrocontext))
@@ -196,7 +206,7 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
 			pu->next = parkinglot;
 			parkinglot = pu;
 			/* If parking a channel directly, don't quiet yet get parking running on it */
-			if (peer == chan)
+			if (peer == chan) 
 				pu->notquiteyet = 1;
 			ast_mutex_unlock(&parking_lock);
 			/* Wake up the (presumably select()ing) thread */
@@ -221,7 +231,6 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
 				if (adsipark && adsi_available(peer)) {
 					adsi_announce_park(peer, pu->parkingnum);
 				}
-				ast_say_digits(peer, pu->parkingnum, "", peer->language);
 				if (adsipark && adsi_available(peer)) {
 					adsi_unload_session(peer);
 				}
@@ -243,6 +252,7 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
 				snprintf(exten, sizeof(exten), "%d", x);
 				ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), free, registrar);
 			}
+			if (peer) ast_say_digits(peer, pu->parkingnum, "", peer->language);
 			return 0;
 		} else {
 			ast_log(LOG_WARNING, "No more parking spaces\n");
@@ -558,6 +568,7 @@ static void *do_parking_thread(void *ignore)
 	struct timeval tv;
 	struct ast_frame *f;
 	char exten[AST_MAX_EXTENSION];
+	char *peername,*cp;
 	struct ast_context *con;
 	int x;
 	int gc=0;
@@ -565,13 +576,13 @@ static void *do_parking_thread(void *ignore)
 	fd_set nrfds, nefds;
 	FD_ZERO(&rfds);
 	FD_ZERO(&efds);
+
 	for (;;) {
 		ms = -1;
 		max = -1;
 		ast_mutex_lock(&parking_lock);
 		pl = NULL;
 		pu = parkinglot;
-		gettimeofday(&tv, NULL);
 		FD_ZERO(&nrfds);
 		FD_ZERO(&nefds);
 		while(pu) {
@@ -585,17 +596,40 @@ static void *do_parking_thread(void *ignore)
 				gc++;
 				ast_moh_start(pu->chan,NULL);
 			}
+			gettimeofday(&tv, NULL);
 			tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
 			if (tms > pu->parkingtime) {
-				/* They've been waiting too long, send them back to where they came.  Theoretically they
-				   should have their original extensions and such, but we copy to be on the safe side */
-				strncpy(pu->chan->exten, pu->exten, sizeof(pu->chan->exten)-1);
-				strncpy(pu->chan->context, pu->context, sizeof(pu->chan->context)-1);
-				pu->chan->priority = pu->priority;
-				if (option_verbose > 1) 
-					ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->chan->context, pu->chan->exten, pu->chan->priority);
 				/* Stop music on hold */
 				ast_moh_stop(pu->chan);
+				/* Get chan, exten from derived kludge */
+				if (pu->peername[0])
+				{
+					peername = strdupa(pu->peername);
+					cp = strrchr(peername,'-');
+					if (cp) *cp = 0;
+					con = ast_context_find(parking_con_dial);
+					if (!con) {
+						con = ast_context_create(NULL,parking_con_dial, registrar);
+						if (!con) {
+							ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
+						}
+					}
+					if (con) {
+						ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(peername), free, registrar);
+					}
+					strncpy(pu->chan->exten, peername, sizeof(pu->chan->exten)-1);
+					strncpy(pu->chan->context, parking_con_dial, sizeof(pu->chan->context)-1);
+					pu->chan->priority = 1;
+
+				} else {
+					/* They've been waiting too long, send them back to where they came.  Theoretically they
+					   should have their original extensions and such, but we copy to be on the safe side */
+					strncpy(pu->chan->exten, pu->exten, sizeof(pu->chan->exten)-1);
+					strncpy(pu->chan->context, pu->context, sizeof(pu->chan->context)-1);
+					pu->chan->priority = pu->priority;
+				}
+				if (option_verbose > 1) 
+					ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->chan->context, pu->chan->exten, pu->chan->priority);
 				/* Start up the PBX, or hang them up */
 				if (ast_pbx_start(pu->chan))  {
 					ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
diff --git a/res/res_monitor.c b/res/res_monitor.c
index c90bab775f25e9ede0b6233c4e4400b32ffdc5f1..e2cec0dacbbe45be2bf302f6bafc24c51a41d1cc 100755
--- a/res/res_monitor.c
+++ b/res/res_monitor.c
@@ -29,7 +29,7 @@ static unsigned long seq = 0;
 
 static char *monitor_synopsis = "Monitor a channel";
 
-static char *monitor_descrip = "Monitor([file_format|[fname_base]|[options]]):\n"
+static char *monitor_descrip = "Monitor([file_format[:urlbase]|[fname_base]|[options]]):\n"
 "Used to start monitoring a channel. The channel's input and output\n"
 "voice packets are logged to files until the channel hangs up or\n"
 "monitoring is stopped by the StopMonitor application.\n"
@@ -307,6 +307,8 @@ static int start_monitor_exec(struct ast_channel *chan, void *data)
 	char *fname_base = NULL;
 	char *options = NULL;
 	char *delay = NULL;
+	char *urlprefix = NULL;
+	char tmp[256];
 	int joinfiles = 0;
 	int waitforbridge = 0;
 	int res = 0;
@@ -315,6 +317,13 @@ static int start_monitor_exec(struct ast_channel *chan, void *data)
 	if (data && !ast_strlen_zero((char*)data)) {
 		arg = ast_strdupa((char*)data);
 		format = arg;
+		arg = strchr(format,':');
+		if (arg)
+		{
+			*arg++ = 0;
+			urlprefix = arg;
+		}
+		else arg = format;
 		fname_base = strchr(arg, '|');
 		if (fname_base) {
 			*fname_base = 0;
@@ -329,7 +338,14 @@ static int start_monitor_exec(struct ast_channel *chan, void *data)
 			}
 		}
 	}
-
+	if (urlprefix)
+	{
+		snprintf(tmp,sizeof(tmp) - 1,"%s/%s.%s",urlprefix,fname_base,
+			((strcmp(format,"gsm")) ? "wav" : "gsm"));
+		if (!chan->cdr)
+			chan->cdr = ast_cdr_alloc();
+		ast_cdr_setuserfield(chan, tmp);
+	}
 	if (waitforbridge) {
 		/* We must remove the "b" option if listed.  In principle none of
 		   the following could give NULL results, but we check just to