From 5235890be44ffebcb332fcaacb0b4e0618fd62db Mon Sep 17 00:00:00 2001
From: BJ Weschke <bweschke@btwtech.com>
Date: Mon, 22 May 2006 16:43:43 +0000
Subject: [PATCH]  This is part 2/2 of the patches for #7090. Adds one-step
 call parking to /trunk via builtin functions and 'k' 'K' application options
 added to app_dial. This also resolves #6340.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@29467 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 apps/app_dial.c              | 17 ++++++++++++++++-
 configs/features.conf.sample |  1 +
 include/asterisk/channel.h   |  1 +
 res/res_features.c           | 32 ++++++++++++++++++++++++++++++++
 4 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/apps/app_dial.c b/apps/app_dial.c
index da44e58200..5c2aec511b 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -183,7 +183,11 @@ static char *descrip =
 "    w    - Allow the called party to enable recording of the call by sending\n"
 "           the DTMF sequence defined for one-touch recording in features.conf.\n"
 "    W    - Allow the calling party to enable recording of the call by sending\n"
-"           the DTMF sequence defined for one-touch recording in features.conf.\n";
+"           the DTMF sequence defined for one-touch recording in features.conf.\n"
+"    k    - Allow the called party to enable parking of the call by sending\n"
+"           the DTMF sequence defined for call parking in features.conf.\n"
+"    K    - Allow the calling party to enable parking of the call by sending\n"
+"           the DTMF sequence defined for call parking in features.conf.\n";
 
 /* RetryDial App by Anthony Minessale II <anthmct@yahoo.com> Jan/2005 */
 static char *rapp = "RetryDial";
@@ -227,6 +231,8 @@ enum {
 	OPT_CALLER_MONITOR =	(1 << 22),
 	OPT_GOTO =		(1 << 23),
 	OPT_OPERMODE = 		(1 << 24),
+	OPT_CALLEE_PARK =	(1 << 25),
+	OPT_CALLER_PARK =	(1 << 26),
 } dial_exec_option_flags;
 
 #define DIAL_STILLGOING			(1 << 30)
@@ -272,6 +278,8 @@ AST_APP_OPTIONS(dial_exec_options, {
 	AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
 	AST_APP_OPTION('w', OPT_CALLEE_MONITOR),
 	AST_APP_OPTION('W', OPT_CALLER_MONITOR),
+	AST_APP_OPTION('k', OPT_CALLEE_PARK),
+	AST_APP_OPTION('K', OPT_CALLER_PARK),
 });
 
 /* We define a custom "local user" structure because we
@@ -441,6 +449,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct dial_l
 						       OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
 						       OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
 						       OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
+						       OPT_CALLEE_PARK | OPT_CALLER_PARK |
 						       DIAL_NOFORWARDHTML);
 				}
 				continue;
@@ -551,6 +560,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct dial_l
 							       OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
 							       OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
 							       OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
+							       OPT_CALLEE_PARK | OPT_CALLER_PARK |
 							       DIAL_NOFORWARDHTML);
 						/* Setup early media if appropriate */
 						ast_rtp_early_media(in, peer);
@@ -1016,6 +1026,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
 				       OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
 				       OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
 				       OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
+				       OPT_CALLEE_PARK | OPT_CALLER_PARK |
 				       OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID);
 			ast_set2_flag(tmp, args.url, DIAL_NOFORWARDHTML);	
 		}
@@ -1497,6 +1508,10 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
 				ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
 			if (ast_test_flag(peerflags, OPT_CALLER_MONITOR)) 
 				ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
+			if (ast_test_flag(peerflags, OPT_CALLEE_PARK))
+				ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
+			if (ast_test_flag(peerflags, OPT_CALLER_PARK))
+				ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
 
 			config.timelimit = timelimit;
 			config.play_warning = play_warning;
diff --git a/configs/features.conf.sample b/configs/features.conf.sample
index 495fa0b61a..db99c4c820 100644
--- a/configs/features.conf.sample
+++ b/configs/features.conf.sample
@@ -32,6 +32,7 @@ context => parkedcalls		; Which context parked calls are in
 ;disconnect => *0		; Disconnect  (default is *)
 ;automon => *1			; One Touch Record a.k.a. Touch Monitor
 ;atxfer => *2			; Attended transfer
+;parkcall => #72                ; Park call (one step parking)
 
 [applicationmap]
 ; Note that the DYNAMIC_FEATURES channel variable must be set to use the features
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index be2bac4d4d..17b6dd159b 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -474,6 +474,7 @@ struct ast_channel {
 #define AST_FEATURE_DISCONNECT		(1 << 2)
 #define AST_FEATURE_ATXFER		(1 << 3)
 #define AST_FEATURE_AUTOMON		(1 << 4)
+#define AST_FEATURE_PARKCALL		(1 << 5)
 
 #define AST_FEATURE_FLAG_NEEDSDTMF	(1 << 0)
 #define AST_FEATURE_FLAG_CALLEE		(1 << 1)
diff --git a/res/res_features.c b/res/res_features.c
index f71f6a9131..8ab36c6c87 100644
--- a/res/res_features.c
+++ b/res/res_features.c
@@ -426,6 +426,37 @@ static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
 	}
 }
 
+static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
+{
+	struct ast_channel *parker;
+        struct ast_channel *parkee;
+
+	int res=0;
+	struct localuser *u;
+	LOCAL_USER_ADD(u);
+
+	set_peers(&parker, &parkee, peer, chan, sense);
+	/* Setup the exten/priority to be s/1 since we don't know
+	   where this call should return */
+	strcpy(chan->exten, "s");
+	chan->priority = 1;
+	if (chan->_state != AST_STATE_UP)
+		res = ast_answer(chan);
+	if (!res)
+		res = ast_safe_sleep(chan, 1000);
+	if (!res)
+		res = ast_park_call(parkee, parker, 0, NULL);
+	LOCAL_USER_REMOVE(u);
+	if (!res) {
+		if (sense == FEATURE_SENSE_CHAN)
+			res = AST_PBX_NO_HANGUP_PEER;
+		else
+			res = AST_PBX_KEEPALIVE;
+	}
+	return res;
+
+}
+
 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
 {
 	char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
@@ -779,6 +810,7 @@ struct ast_call_feature builtin_features[] =
 	{ AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
 	{ AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
 	{ AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
+	{ AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF },
 };
 
 
-- 
GitLab