MEDIUM: cli: handle payload in CLI proxy

The CLI proxy was not handling payload. To do that, we needed to keep a
connection active on a server and to transfer each new line over that
connection until we receive a empty line.

The CLI proxy handles the payload in the same way that the CLI do it.

Examples:

   $ echo -e "@1;add map #-1 <<\n$(cat data)\n" | socat /tmp/master-socket -

   $ socat /tmp/master-socket readline
   prompt
   master> @1
   25130> add map #-1 <<
   + test test
   + test2 test2
   + test3 test3
   +

   25130>
diff --git a/src/cli.c b/src/cli.c
index 3af5c6a..9d210dd 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -1661,10 +1661,14 @@
 	if (!s->pcli_prompt)
 		return;
 
-	if (s->pcli_next_pid == 0)
-		chunk_appendf(msg, "master> ");
-	else
-		chunk_appendf(msg, "%d> ", s->pcli_next_pid);
+	if (s->pcli_flags & APPCTX_CLI_ST1_PAYLOAD) {
+		chunk_appendf(msg, "+ ");
+	} else {
+		if (s->pcli_next_pid == 0)
+			chunk_appendf(msg, "master> ");
+		else
+			chunk_appendf(msg, "%d> ", s->pcli_next_pid);
+	}
 	co_inject(oc, msg->area, msg->data);
 }
 
@@ -1815,26 +1819,39 @@
 	int argl; /* number of args */
 	char *p;
 	char *trim = NULL;
+	char *payload = NULL;
 	int wtrim = 0; /* number of words to trim */
 	int reql = 0;
 	int i = 0;
 
 	p = str;
 
-	/* Looks for the end of one command */
-	while (p+reql < end) {
-		/* handle escaping */
-		if (str[reql] == '\\') {
+	if (!(s->pcli_flags & APPCTX_CLI_ST1_PAYLOAD)) {
+
+		/* Looks for the end of one command */
+		while (p+reql < end) {
+			/* handle escaping */
+			if (p[reql] == '\\') {
+				reql++;
+				continue;
+			}
+			if (p[reql] == ';' || p[reql] == '\n') {
+				/* found the end of the command */
+				p[reql] = '\n';
+				reql++;
+				break;
+			}
 			reql++;
-			continue;
 		}
-		if (str[reql] == ';' || str[reql] == '\n') {
-			/* found the end of the command */
-			str[reql] = '\n';
+	} else {
+		while (p+reql < end) {
+			if (p[reql] == '\n') {
+				/* found the end of the line */
+				reql++;
+				break;
+			}
 			reql++;
-			break;
 		}
-		reql++;
 	}
 
 	/* set end to first byte after the end of the command */
@@ -1845,6 +1862,19 @@
 		return -1;
 	}
 
+	/* last line of the payload */
+	if ((s->pcli_flags & APPCTX_CLI_ST1_PAYLOAD) && (reql == 1)) {
+		s->pcli_flags &= ~APPCTX_CLI_ST1_PAYLOAD;
+		return reql;
+	}
+
+	payload = strstr(p, PAYLOAD_PATTERN);
+	if ((end - 1) == (payload + strlen(PAYLOAD_PATTERN))) {
+		/* if the payload pattern is at the end */
+		s->pcli_flags |= APPCTX_CLI_ST1_PAYLOAD;
+		return reql;
+	}
+
 	*(end-1) = '\0';
 
 	/* splits the command in words */
@@ -1952,8 +1982,15 @@
 
 		/* forward only 1 command */
 		channel_forward(req, to_forward);
-		/* we send only 1 command per request, and we write close after it */
-		channel_shutw_now(req);
+
+		if (!(s->pcli_flags & APPCTX_CLI_ST1_PAYLOAD)) {
+			/* we send only 1 command per request, and we write close after it */
+			channel_shutw_now(req);
+		} else {
+			pcli_write_prompt(s);
+		}
+
+		s->res.flags |= CF_WAKE_ONCE; /* need to be called again */
 
 		/* remove the XFER_DATA analysers, which forwards all
 		 * the data, we don't want to forward the next requests
@@ -1963,15 +2000,17 @@
 		req->analysers |= AN_REQ_FLT_END|CF_FLT_ANALYZE;
 		s->res.analysers |= AN_RES_WAIT_CLI;
 
-		if (next_pid > -1)
-			target_pid = next_pid;
-		else
-			target_pid = s->pcli_next_pid;
-		/* we can connect now */
-		s->target = pcli_pid_to_server(target_pid);
+		if (!(s->flags & SF_ASSIGNED)) {
+			if (next_pid > -1)
+				target_pid = next_pid;
+			else
+				target_pid = s->pcli_next_pid;
+			/* we can connect now */
+			s->target = pcli_pid_to_server(target_pid);
 
-		s->flags |= (SF_DIRECT | SF_ASSIGNED);
-		channel_auto_connect(req);
+			s->flags |= (SF_DIRECT | SF_ASSIGNED);
+			channel_auto_connect(req);
+		}
 
 	} else if (to_forward == 0) {
 		/* we trimmed things but we might have other commands to consume */
@@ -2011,6 +2050,13 @@
 	channel_dont_close(&s->res);
 	channel_dont_close(&s->req);
 
+	if (s->pcli_flags & APPCTX_CLI_ST1_PAYLOAD) {
+		s->req.analysers |= AN_REQ_WAIT_CLI;
+		s->res.analysers &= ~AN_RES_WAIT_CLI;
+		s->req.flags |= CF_WAKE_ONCE; /* need to be called again if there is some command left in the request */
+		return 0;
+	}
+
 	/* forward the data */
 	if (ci_data(rep)) {
 		c_adv(rep, ci_data(rep));