patch 7.4.1341
Problem:    It's difficult to add more arguments to ch_sendraw() and
            ch_sendexpr().
Solution:   Make the third option a dictionary.
diff --git a/src/channel.c b/src/channel.c
index 3cfe1be..d4663d8 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -697,6 +697,18 @@
 }
 
 /*
+ * Set various properties from an "options" argument.
+ */
+    void
+channel_set_options(channel_T *channel, jobopt_T *options)
+{
+    channel_set_mode(channel, options->jo_mode);
+
+    if (options->jo_callback != NULL && *options->jo_callback != NUL)
+	channel_set_callback(channel, options->jo_callback);
+}
+
+/*
  * Set the callback for channel "channel" for the response with "id".
  */
     void
diff --git a/src/eval.c b/src/eval.c
index 8e4e540..f47b096 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -9930,15 +9930,18 @@
 }
 
 /*
- * Get the "mode" entry from "dict", if it exists, and parse the mode name.
- * If the mode is invalide return FAIL.
+ * Get the option entries from "dict", and parse them.
+ * If an option value is invalid return FAIL.
  */
     static int
-get_mode_arg(dict_T *dict, jobopt_T *opt)
+get_job_options(dict_T *dict, jobopt_T *opt)
 {
     dictitem_T	*item;
     char_u	*mode;
 
+    if (dict == NULL)
+	return OK;
+
     if ((item = dict_find(dict, (char_u *)"mode", -1)) != NULL)
     {
 	mode = get_tv_string(&item->di_tv);
@@ -9956,6 +9959,17 @@
 	    return FAIL;
 	}
     }
+
+    if ((item = dict_find(dict, (char_u *)"callback", -1)) != NULL)
+    {
+	opt->jo_callback = get_callback(&item->di_tv);
+	if (opt->jo_callback == NULL)
+	{
+	    EMSG2(_(e_invarg2), "callback");
+	    return FAIL;
+	}
+    }
+
     return OK;
 }
 
@@ -9966,7 +9980,6 @@
 f_ch_open(typval_T *argvars, typval_T *rettv)
 {
     char_u	*address;
-    char_u	*callback = NULL;
     char_u	*p;
     char	*rest;
     int		port;
@@ -10004,20 +10017,19 @@
     }
 
     options.jo_mode = MODE_JSON;
+    options.jo_callback = NULL;
     if (argvars[1].v_type == VAR_DICT)
     {
 	dict_T	    *dict = argvars[1].vval.v_dict;
 	dictitem_T  *item;
 
 	/* parse argdict */
-	if (get_mode_arg(dict, &options) == FAIL)
+	if (get_job_options(dict, &options) == FAIL)
 	    return;
 	if ((item = dict_find(dict, (char_u *)"waittime", -1)) != NULL)
 	    waittime = get_tv_number(&item->di_tv);
 	if ((item = dict_find(dict, (char_u *)"timeout", -1)) != NULL)
 	    timeout = get_tv_number(&item->di_tv);
-	if ((item = dict_find(dict, (char_u *)"callback", -1)) != NULL)
-	    callback = get_callback(&item->di_tv);
     }
     if (waittime < 0 || timeout < 0)
     {
@@ -10029,10 +10041,8 @@
     if (channel != NULL)
     {
 	rettv->vval.v_channel = channel;
-	channel_set_mode(channel, options.jo_mode);
+	channel_set_options(channel, &options);
 	channel_set_timeout(channel, timeout);
-	if (callback != NULL && *callback != NUL)
-	    channel_set_callback(channel, callback);
     }
 }
 
@@ -10082,6 +10092,7 @@
 {
     channel_T	*channel;
     char_u	*callback = NULL;
+    jobopt_T	options;
 
     channel = get_channel_arg(&argvars[0]);
     if (channel == NULL)
@@ -10089,9 +10100,15 @@
 
     if (argvars[2].v_type != VAR_UNKNOWN)
     {
-	callback = get_callback(&argvars[2]);
-	if (callback == NULL)
+	if (argvars[2].v_type != VAR_DICT)
+	{
+	    EMSG(_(e_invarg));
 	    return NULL;
+	}
+	options.jo_callback = NULL;
+	if (get_job_options(argvars[2].vval.v_dict, &options) == FAIL)
+	    return NULL;
+	callback = options.jo_callback;
     }
     /* Set the callback. An empty callback means no callback and not reading
      * the response. */
@@ -14511,17 +14528,15 @@
 
     /* Default mode is NL. */
     options.jo_mode = MODE_NL;
+    options.jo_callback = NULL;
     if (argvars[1].v_type != VAR_UNKNOWN)
     {
-	dict_T	    *dict;
-
 	if (argvars[1].v_type != VAR_DICT)
 	{
 	    EMSG(_(e_invarg));
 	    return;
 	}
-	dict = argvars[1].vval.v_dict;
-	if (get_mode_arg(dict, &options) == FAIL)
+	if (get_job_options(argvars[1].vval.v_dict, &options) == FAIL)
 	    return;
     }
 
diff --git a/src/os_unix.c b/src/os_unix.c
index 0059c9e..1f0f2c8 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -5127,7 +5127,7 @@
 # ifdef FEAT_CHANNEL
     channel_set_pipes(channel, fd_in[1], fd_out[0], fd_err[0]);
     channel_set_job(channel, job);
-    channel_set_mode(channel, options->jo_mode);
+    channel_set_options(channel, options);
 #  ifdef FEAT_GUI
     channel_gui_register(channel);
 #  endif
diff --git a/src/os_win32.c b/src/os_win32.c
index eaa8ba5..63d7d60 100644
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -5125,7 +5125,7 @@
     job->jv_channel = channel;
     channel_set_pipes(channel, (sock_T)ifd[1], (sock_T)ofd[0], (sock_T)efd[0]);
     channel_set_job(channel, job);
-    channel_set_mode(channel, options->jo_mode);
+    channel_set_options(channel, options);
 
 #   ifdef FEAT_GUI
      channel_gui_register(channel);
diff --git a/src/proto/channel.pro b/src/proto/channel.pro
index e1c8862..a4acfe6 100644
--- a/src/proto/channel.pro
+++ b/src/proto/channel.pro
@@ -7,9 +7,10 @@
 channel_T *channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void));
 void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
 void channel_set_job(channel_T *channel, job_T *job);
-void channel_set_mode(channel_T *channel, ch_mode_T ch_mode);
+void channel_set_mode(channel_T *channel, ch_mode_T mode);
 void channel_set_timeout(channel_T *channel, int timeout);
 void channel_set_callback(channel_T *channel, char_u *callback);
+void channel_set_options(channel_T *channel, jobopt_T *options);
 void channel_set_req_callback(channel_T *channel, char_u *callback, int id);
 char_u *channel_get(channel_T *channel);
 int channel_collapse(channel_T *channel);
diff --git a/src/structs.h b/src/structs.h
index eb72f90..802180b 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1373,11 +1373,12 @@
 };
 
 /*
- * Options for job commands.
+ * Options for job and channel commands.
  */
 typedef struct
 {
-    ch_mode_T	jo_mode;
+    ch_mode_T	jo_mode;	/* "mode" */
+    char_u	*jo_callback;	/* "callback", not allocated! */
 } jobopt_T;
 
 
diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim
index e9c2a98..7cd32c8 100644
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -117,7 +117,7 @@
   call assert_equal('added more', getline('$'))
 
   " Send a request with a specific handler.
-  call ch_sendexpr(handle, 'hello!', 's:RequestHandler')
+  call ch_sendexpr(handle, 'hello!', {'callback': 's:RequestHandler'})
   sleep 10m
   if !exists('s:responseHandle')
     call assert_false(1, 's:responseHandle was not set')
@@ -128,7 +128,7 @@
 
   unlet s:responseHandle
   let s:responseMsg = ''
-  call ch_sendexpr(handle, 'hello!', function('s:RequestHandler'))
+  call ch_sendexpr(handle, 'hello!', {'callback': function('s:RequestHandler')})
   sleep 10m
   if !exists('s:responseHandle')
     call assert_false(1, 's:responseHandle was not set')
@@ -171,7 +171,7 @@
   call assert_equal('ok', ch_sendexpr(handle, 'empty-request'))
 
   " make the server quit, can't check if this works, should not hang.
-  call ch_sendexpr(handle, '!quit!', 0)
+  call ch_sendexpr(handle, '!quit!', {'callback': 0})
 endfunc
 
 func Test_communicate()
@@ -242,7 +242,7 @@
   call assert_equal('we called you', s:reply)
 
   " Test that it works while not waiting on a numbered message.
-  call ch_sendexpr(handle, 'call me again', 0)
+  call ch_sendexpr(handle, 'call me again', {'callback': 0})
   sleep 10m
   call assert_equal('we did call you', s:reply)
 endfunc
@@ -292,11 +292,11 @@
   call assert_equal("run", job_status(job))
   try
     let handle = job_getchannel(job)
-    call ch_sendraw(handle, "echo something\n", 0)
+    call ch_sendraw(handle, "echo something\n", {'callback': 0})
     let msg = ch_readraw(handle)
     call assert_equal("something\n", substitute(msg, "\r", "", 'g'))
 
-    call ch_sendraw(handle, "double this\n", 0)
+    call ch_sendraw(handle, "double this\n", {'callback': 0})
     let msg = ch_readraw(handle)
     call assert_equal("this\nAND this\n", substitute(msg, "\r", "", 'g'))
 
@@ -315,10 +315,10 @@
   call assert_equal("run", job_status(job))
   try
     let handle = job_getchannel(job)
-    call ch_sendraw(handle, "echo something\n", 0)
+    call ch_sendraw(handle, "echo something\n", {'callback': 0})
     call assert_equal("something", ch_readraw(handle))
 
-    call ch_sendraw(handle, "double this\n", 0)
+    call ch_sendraw(handle, "double this\n", {'callback': 0})
     call assert_equal("this", ch_readraw(handle))
     call assert_equal("AND this", ch_readraw(handle))
 
@@ -340,7 +340,7 @@
 " Test that "unlet handle" in a handler doesn't crash Vim.
 func s:unlet_handle(port)
   let s:channelfd = ch_open('localhost:' . a:port, s:chopt)
-  call ch_sendexpr(s:channelfd, "test", function('s:UnletHandler'))
+  call ch_sendexpr(s:channelfd, "test", {'callback': function('s:UnletHandler')})
   sleep 10m
   call assert_equal('what?', s:unletResponse)
 endfunc
@@ -360,7 +360,7 @@
 " Test that "unlet handle" in a handler doesn't crash Vim.
 func s:close_handle(port)
   let s:channelfd = ch_open('localhost:' . a:port, s:chopt)
-  call ch_sendexpr(s:channelfd, "test", function('s:CloseHandler'))
+  call ch_sendexpr(s:channelfd, "test", {'callback': function('s:CloseHandler')})
   sleep 10m
   call assert_equal('what?', s:unletResponse)
 endfunc
diff --git a/src/version.c b/src/version.c
index 9821bdf..f7c008c 100644
--- a/src/version.c
+++ b/src/version.c
@@ -748,6 +748,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1341,
+/**/
     1340,
 /**/
     1339,