From 540b7c48c9e13910105ab67146b54a43db9fc253 Mon Sep 17 00:00:00 2001
From: patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>
Date: Sat, 28 Mar 2009 19:49:28 +0000
Subject: [PATCH] Add wget command to NSH

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1657 42af7a65-404d-4744-a932-0658087f49c3
---
 ChangeLog                            |   8 +-
 Documentation/NuttShell.html         |  46 +++++++-
 Documentation/NuttX.html             |   8 +-
 Documentation/NuttxPortingGuide.html |   2 +-
 TODO                                 |  28 +++--
 examples/nsh/README.txt              |  19 +++-
 examples/nsh/nsh.h                   |   5 +
 examples/nsh/nsh_main.c              |   6 ++
 examples/nsh/nsh_netcmds.c           | 154 ++++++++++++++++++++++++++-
 examples/wget/host.c                 |   5 +-
 examples/wget/target.c               |   5 +-
 include/net/uip/webclient.h          |   5 +-
 netutils/webclient/webclient.c       |   4 +-
 13 files changed, 265 insertions(+), 30 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index e250ac7ef9..922ba77cf8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -672,6 +672,10 @@
 	  (submitted by JPelletier).  The is the same fix that was needed for the
 	  eZ80 and fixed in 0.4.2.
 	* netutils: Added logic to support a simple wget() function
-	* examples/wget: Added a test for wget() (Not yet tested because of
-	  some current networking limitations).
+	* examples/wget: Added a test for wget()  -- NOTE
 	* lib/strncasecmp: Fix cut'n'paste error in function name.
+	* NSH: Added wget command (untested and temorarily disabled)-- see NOTE.
+
+	NOTE: Features related to wget are not tested on the target platform in this
+	release and, hence, most likely have problems.  I don't have the correct network
+	settup to perform that testing now (I'm in a hotel).
diff --git a/Documentation/NuttShell.html b/Documentation/NuttShell.html
index c5c5c921be..2ebad0a744 100644
--- a/Documentation/NuttShell.html
+++ b/Documentation/NuttShell.html
@@ -8,7 +8,7 @@
   <tr align="center" bgcolor="#e4e4e4">
     <td>
       <h1><big><font color="#3c34ec"><i>NuttShell (NSH)</i></font></big></h1>
-      <p>Last Updated: November 15, 2008</p>
+      <p>Last Updated: March 28, 2009</p>
     </td>
   </tr>
 </table>
@@ -275,7 +275,13 @@
 <tr>
   <td><br></td>
   <td>
-    <a href="#cmdxd">2.33 Hexadecimal Dump (xd)</a>
+    <a href="#cmdwget">2.33 Get File Via HTTP (wget)</a>
+  </td>
+</tr>
+<tr>
+  <td><br></td>
+  <td>
+    <a href="#cmdxd">2.34 Hexadecimal Dump (xd)</a>
   </td>
 </tr>
 <tr>
@@ -1673,7 +1679,34 @@ usleep &lt;usec&gt;
 <table width ="100%">
   <tr bgcolor="#e4e4e4">
   <td>
-    <a name="cmdxd"><h2>2.33 Hexadecimal dump (xd)</h2></a>
+    <a name="cmdwget">2.33 Get File Via HTTP (wget)</a>
+  </td>
+  </tr>
+</table>
+
+<a <p><b>Command Syntax:</b></p>
+<ul><pre>
+wget [-o &lt;local-path&gt;] &lt;url&gt;
+</pre></ul>
+<p>
+  <b>Synopsis</b>.
+  Use HTTP to copy the file at <code>&lt;url&gt;</code> to the current directory.
+</p>
+<p><b>Options:</b></p>
+<ul><table>
+  <tr>
+    <td><b><code>-o &lt;local-path&gt;</code></b></td>
+    <td>
+      The file will be saved relative to the current working directory
+      and with the same name as on the HTTP server unless <code>&lt;local-path&gt;</code> is provided.
+    </td>
+  </tr>
+</table></ul>
+
+<table width ="100%">
+  <tr bgcolor="#e4e4e4">
+  <td>
+    <a name="cmdxd"><h2>2.34 Hexadecimal dump (xd)</h2></a>
   </td>
   </tr>
 </table>
@@ -1909,6 +1942,12 @@ nsh>
     <td>!<code>CONFIG_DISABLE_SIGNALS</code></td>
     <td><code>CONFIG_EXAMPLES_NSH_DISABLE_USLEEP</code></td>
   </tr>
+  <tr>
+    <td><b><code>wget</code></b></td>
+    <td><code>CONFIG_NET</code> &amp;&amp; <code>CONFIG_NET_TCP</code> &amp;&amp;
+        <code>CONFIG_NFILE_DESCRIPTORS</code> &gt; 0</td>
+    <td><code>CONFIG_EXAMPLES_NSH_DISABLE_WGET</code></td>
+  </tr>
   <tr>
     <td><b><code>xd</code></b></td>
     <td><br></td>
@@ -2255,6 +2294,7 @@ nsh>
   <li><a href="#cmdunmount"><code>umount</code></a></li>
   <li><a href="#cmdunset"><code>unset</code></a></li>
   <li><a href="#cmdusleep"><code>usleep</code></a></li>
+  <li><a href="#cmdwget"><code>wget</code></a></li>
   <li><a href="#cmdxd"><code>xd</code></a></li>
 </ul></td>
 </tr></table>
diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html
index a592cf57a5..382c2d3ad4 100644
--- a/Documentation/NuttX.html
+++ b/Documentation/NuttX.html
@@ -1363,9 +1363,13 @@ nuttx-0.4.4 2009-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
 	  (submitted by JPelletier).  The is the same fix that was needed for the
 	  eZ80 and fixed in 0.4.2.
 	* netutils: Added logic to support a simple wget() function
-	* examples/wget: Added a test for wget() (Not yet tested because of
-	  some current networking limitations).
+	* examples/wget: Added a test for wget()  -- NOTE
 	* lib/strncasecmp: Fix cut'n'paste error in function name.
+	* NSH: Added wget command (untested and temorarily disabled)-- see NOTE.
+
+	NOTE: Features related to wget are not tested on the target platform in this
+	release and, hence, most likely have problems.  I don't have the correct network
+	settup to perform that testing now (I'm in a hotel).
 
 pascal-0.1.3 2009-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
 
diff --git a/Documentation/NuttxPortingGuide.html b/Documentation/NuttxPortingGuide.html
index 93a2e3b2ee..1d790ee25d 100644
--- a/Documentation/NuttxPortingGuide.html
+++ b/Documentation/NuttxPortingGuide.html
@@ -817,7 +817,7 @@ include/
 <h2>2.12 <a name="DirStructNetUtils">netutils</a></h2>
 <p>
   This directory contains most of the network applications.
-  Some of these are original with NuttX (like tftpc) and others were leveraged from the uIP-1.0 apps directory.
+  Some of these are original with NuttX (like tftpc and dhcpd) and others were leveraged from the uIP-1.0 apps directory.
   As the uIP apps/README says, these applications &quot;are not all heavily tested.&quot;
 </p>
 <ul><pre>
diff --git a/TODO b/TODO
index 763d088893..32aee97ece 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,5 @@
-NuttX TODO List (Last updated February 19, 2009)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+NuttX TODO List (Last updated March 28, 2009)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
   (6)  Task/Scheduler (sched/)
   (1)  Dynamic loader (N/A)
@@ -16,7 +16,7 @@ NuttX TODO List (Last updated February 19, 2009)
   (2)  Documentation (Documentation/)
   (5)  Build system / Toolchains
   (2)  NuttShell (NSH) (examples/nsh)
-  (1)  Other Applications & Tests (examples/)
+  (2)  Other Applications & Tests (examples/)
   (1)  Linux/Cywgin simulation (arch/sim)
   (2)  ARM (arch/arm/)
   (1)  ARM/C5471 (arch/arm/src/c5471/)
@@ -120,8 +120,10 @@ o Network (net/, netutils/)
   ^^^^^^^^^^^^^^^^^^^^^^^^^
 
   Description: Several of the netutils/ apps are untested.  These include
-               uIP's netutils/smtp, dhcpd, resolv, webclient.  Only minimal
-               testing of the others has been performed.
+               uIP's netutils/smtp and resolv.  The webclient code has been
+               tested on host using gethosbyname(), but not depends on the
+               untested resolve logic. Only minimal testing of the others
+               has been performed.
   Status:      Open
   Priority:    Medium, Important but not core NuttX functionality
 
@@ -381,10 +383,13 @@ o NuttShell (NSH) (examples/nsh)
   Status:      Open
   Priority:    Low
 
-  Description: Here are some commands that would be good to have in NSH:
-               ping
+  Description: The wget command has been incorporated into NSH, however
+               it is still untested as of this writing (only because I
+               have not had the correct network setup for the testing
+               yet).  Since wget depends on the also untest uIP resolv/
+               logic, it is like non-functional.
   Status:      Open
-  Priority:    Low
+  Priority:    Med-High
 
 o Other Applications & Tests (examples/)
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -392,6 +397,13 @@ o Other Applications & Tests (examples/)
   Description: The redirection test (part of examples/pipe) terminates
                incorrectly on the Cywgin-based simulation platform (but works
                fine on the Linux-based simulation platform).
+  Status:      Open
+  Priority:    Low
+
+  Description: examples/wget is untested on the target (it has been tested
+               on the host, but not in the target using the uIP resolv logic).
+  Status:      Open
+  Priority:    Med
 
 o Linux/Cywgin simulation (arch/sim)
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/examples/nsh/README.txt b/examples/nsh/README.txt
index 8bdd14eb50..2a8d43f48b 100644
--- a/examples/nsh/README.txt
+++ b/examples/nsh/README.txt
@@ -303,8 +303,8 @@ o exit
 
 o get [-b|-n] [-f <local-path>] -h <ip-address> <remote-path>
 
-  Copy the file at <remote-address> from the host whose IP address is
-  identified by <ip-address>.  Other options:
+  Use TFTP to copy the file at <remote-address> from the host whose IP
+  address is identified by <ip-address>.  Other options:
 
   -f <local-path>
      The file will be saved relative to the current working directory
@@ -717,6 +717,16 @@ o usleep <usec>
 
   Pause execution (sleep) of <usec> microseconds.
 
+o wget [-o <local-path>] <url>
+
+  Use HTTP to copy the file at <url> to the current directory.
+  Options:
+
+  -o <local-path>
+     The file will be saved relative to the current working directory
+     and with the same name as on the HTTP server unless <local-path>
+     is provided.
+
 o xd <hex-address> <byte-count>
 
   Dump <byte-count> bytes of data from address <hex-address>
@@ -780,10 +790,11 @@ Command Dependencies on Configuration Settings
   umount     !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_READABLE
   unset      !CONFIG_DISABLE_ENVIRON
   usleep     !CONFIG_DISABLE_SIGNALS
+  get        CONFIG_NET && CONFIG_NET_TCP && CONFIG_NFILE_DESCRIPTORS > 0
   xd         ---
 
 * NOTES:
-  1. Because of hardware padding, the actual required for put and get
+  1. Because of hardware padding, the actual buffersize required for put and get
      operations size may be larger.
   2. Special TFTP server start-up optionss will probably be required to permit
      creation of file for the correct operation of the put command.
@@ -808,7 +819,7 @@ also allow it to squeeze into very small memory footprints.
   CONFIG_EXAMPLES_NSH_DISABLE_PWD,      CONFIG_EXAMPLES_NSH_DISABLE_RM,      CONFIG_EXAMPLES_NSH_DISABLE_RMDIR,
   CONFIG_EXAMPLES_NSH_DISABLE_SET,      CONFIG_EXAMPLES_NSH_DISABLE_SH,      CONFIG_EXAMPLES_NSH_DISABLE_SLEEP,
   CONFIG_EXAMPLES_NSH_DISABLE_TEST,     CONFIG_EXAMPLES_NSH_DISABLE_UMOUNT,  CONFIG_EXAMPLES_NSH_DISABLE_UNSET,
-  CONFIG_EXAMPLES_NSH_DISABLE_USLEEP,   CONFIG_EXAMPLES_NSH_DISABLE_XD
+  CONFIG_EXAMPLES_NSH_DISABLE_USLEEP,   CONFIG_EXAMPLES_NSH_DISABLE_WGET,    CONFIG_EXAMPLES_NSH_DISABLE_XD
 
 NSH-Specific Configuration Settings
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/examples/nsh/nsh.h b/examples/nsh/nsh.h
index 0ef0baaecc..4a986a9965 100644
--- a/examples/nsh/nsh.h
+++ b/examples/nsh/nsh.h
@@ -434,6 +434,11 @@ extern int cmd_lbracket(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
      extern int cmd_put(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
 #  endif
 #endif
+#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0
+#  ifndef CONFIG_EXAMPLES_NSH_DISABLE_WGET
+     extern int cmd_wget(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#  endif
+#endif
 #if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \
    !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_DISABLE_SIGNALS)
 #  ifndef CONFIG_EXAMPLES_NSH_DISABLE_PING
diff --git a/examples/nsh/nsh_main.c b/examples/nsh/nsh_main.c
index db116b5c05..edcdf131da 100644
--- a/examples/nsh/nsh_main.c
+++ b/examples/nsh/nsh_main.c
@@ -317,6 +317,12 @@ static const struct cmdmap_s g_cmdmap[] =
 # endif
 #endif
 
+#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_GET
+  { "wget",     cmd_wget,     2, 3, "[-o <local-path>] <url>" },
+# endif
+#endif
+
 #ifndef CONFIG_EXAMPLES_NSH_DISABLE_XD
   { "xd",       cmd_xd,       3, 3, "<hex-address> <byte-count>" },
 #endif
diff --git a/examples/nsh/nsh_netcmds.c b/examples/nsh/nsh_netcmds.c
index f95e450171..f9e0acc6c2 100644
--- a/examples/nsh/nsh_netcmds.c
+++ b/examples/nsh/nsh_netcmds.c
@@ -1,7 +1,7 @@
 /****************************************************************************
  * examples/nsh/nsh_netcmds.c
  *
- *   Copyright (C) 2007, 2008, 2009 Gregory Nutt. All rights reserved.
+ *   Copyright (C) 2007-2009 Gregory Nutt. All rights reserved.
  *   Author: Gregory Nutt <spudmonkey@racsa.co.cr>
  *
  * Redistribution and use in source and binary forms, with or without
@@ -41,12 +41,14 @@
 #ifdef CONFIG_NET
 
 #include <sys/types.h>
+#include <sys/stat.h>    /* Needed for open */
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <sched.h>
-#include <libgen.h>
+#include <fcntl.h>       /* Needed for open */
+#include <libgen.h>      /* Needed for basename */
 #include <errno.h>
 
 #include <nuttx/net.h>
@@ -70,6 +72,13 @@
 #  include <net/uip/tftp.h>
 #endif
 
+#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0
+#  ifndef CONFIG_EXAMPLES_NSH_DISABLE_WGET
+#    include <net/uip/uip-lib.h>
+#    include <net/uip/webclient.h>
+#  endif
+#endif
+
 #include "nsh.h"
 
 /****************************************************************************
@@ -302,9 +311,11 @@ int tftpc_parseargs(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv,
 
           case ':':
             fmt = g_fmtargrequired;
+            goto errout;
 
           case '?':
           default:
+            fmt = g_fmtarginvalid;
             goto errout;
         }
     }
@@ -378,6 +389,20 @@ errout:
 }
 #endif
 
+/****************************************************************************
+ * Name: wget_callback
+ ****************************************************************************/
+
+#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_WGET
+static void wget_callback(FAR char **buffer, int offset, int datend,
+                          FAR int *buflen, FAR void *arg)
+{
+  (void)write((int)arg, &((*buffer)[offset]), datend - offset);
+}
+#endif
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -626,4 +651,129 @@ int cmd_put(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
 #endif
 #endif
 
+/****************************************************************************
+ * Name: cmd_wget
+ ****************************************************************************/
+
+#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_WGET
+int cmd_wget(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+  char *localfile = NULL;
+  char *allocfile = NULL;
+  char *buffer    = NULL;
+  char *fullpath  = NULL;
+  char *url;
+  char *fmt;
+  int option;
+  int fd = -1;
+  int ret;
+
+  /* Get the wget options */
+
+  while ((option = getopt(argc, argv, ":o:")) != ERROR)
+    {
+      switch (option)
+        {
+          case 'o':
+            localfile = optarg;
+            break;
+
+          case ':':
+            fmt = g_fmtargrequired;
+            goto errout;
+
+          case '?':
+          default:
+            fmt = g_fmtarginvalid;
+            goto errout;
+        }
+    }
+
+  /* There should be exactly on parameter left on the command-line */
+
+  if (optind == argc-1)
+    {
+      url = argv[optind];
+    }
+  else if (optind >= argc)
+    {
+      fmt = g_fmttoomanyargs;
+      goto errout;
+    }
+  else
+    {
+      fmt = g_fmtargrequired;
+      goto errout;
+    }
+
+  /* Get the local file name */
+
+  if (!localfile)
+    {
+      allocfile = strdup(url);
+      localfile = basename(allocfile);
+    }
+
+  /* Get the full path to the local file */
+
+  fullpath = nsh_getfullpath(vtbl, localfile);
+
+  /* Open the the local file for writing */
+
+  fd = open(fullpath, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+  if (fd < 0)
+    {
+      nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO);
+      ret = ERROR;
+      goto exit;
+    }
+
+  /* Allocate an I/O buffer */
+
+  buffer = malloc(512);
+  if (!buffer)
+    {
+      fmt = g_fmtcmdoutofmemory;
+      goto errout;
+    }
+
+  /* And perform the wget */
+
+  ret = wget(argv[1], buffer, 512, wget_callback, (FAR void *)fd);
+  if (ret < 0)
+    {
+      nsh_output(vtbl, g_fmtcmdfailed, argv[0], "wget", NSH_ERRNO);
+      goto exit;
+     }
+
+  /* Free allocated resources */
+
+exit:
+  if (fd >= 0)
+    {
+      close(fd);
+    }
+  if (allocfile)
+    {
+      free(allocfile);
+    }
+  if (fullpath)
+    {
+      free(fullpath);
+    }
+  if (buffer)
+    {
+      free(buffer);
+    }
+  return ret;
+
+errout:
+  nsh_output(vtbl, fmt, argv[0]);
+  ret = ERROR;
+  goto exit;
+}
+#endif
+#endif
+
 #endif /* CONFIG_NET */
diff --git a/examples/wget/host.c b/examples/wget/host.c
index 6d59e0eb10..40fda1af98 100644
--- a/examples/wget/host.c
+++ b/examples/wget/host.c
@@ -56,7 +56,8 @@
  * Name: callback
  ****************************************************************************/
 
-static void callback(FAR char **buffer, int offset, int datend, FAR int *buflen)
+static void callback(FAR char **buffer, int offset, int datend,
+                     FAR int *buflen, FAR void *arg)
 {
   (void)write(1, &((*buffer)[offset]), datend - offset);
 }
@@ -89,7 +90,7 @@ int main(int argc, char **argv, char **envp)
     }
 
   printf("WGET: Getting %s\n", argv[1]);
-  ret = wget(argv[1], buffer, 1024, callback);
+  ret = wget(argv[1], buffer, 1024, callback, NULL);
   if (ret < 0)
     {
       fprintf(stderr, "WGET: wget failed: %s\n", strerror(errno));
diff --git a/examples/wget/target.c b/examples/wget/target.c
index 89716014c6..9d34769641 100644
--- a/examples/wget/target.c
+++ b/examples/wget/target.c
@@ -94,7 +94,8 @@ static char g_iobuffer[512];
  * Name: callback
  ****************************************************************************/
 
-static void callback(FAR char **buffer, int offset, int datend, FAR int *buflen)
+static void callback(FAR char **buffer, int offset, int datend,
+                     FAR int *buflen, FAR void *arg)
 {
   (void)write(1, &((*buffer)[offset]), datend - offset);
 }
@@ -155,6 +156,6 @@ int user_start(int argc, char *argv[])
 
   /* Then start the server */
   
-  wget(CONFIG_EXAMPLE_WGET_URL, g_iobuffer, 512, callback);
+  wget(CONFIG_EXAMPLE_WGET_URL, g_iobuffer, 512, callback, NULL);
   return 0;
 }
diff --git a/include/net/uip/webclient.h b/include/net/uip/webclient.h
index 053dd5613e..13787e2db3 100644
--- a/include/net/uip/webclient.h
+++ b/include/net/uip/webclient.h
@@ -96,7 +96,7 @@
  */
 
 typedef void (*wget_callback_t)(FAR char **buffer, int offset,
-                                int datend, FAR int *buflen);
+                                int datend, FAR int *buflen, FAR void *arg);
 
 /****************************************************************************
  * Public Function Prototypes
@@ -130,6 +130,7 @@ extern "C" {
  *   buflen   - The size of the user provided buffer
  *   callback - As data is obtained from the host, this function is
  *              to dispose of each block of file data as it is received.
+ *   arg      - User argument passed to callback.
  *
  * Returned Value:
  *   0: if the GET operation completed successfully;
@@ -138,7 +139,7 @@ extern "C" {
  ****************************************************************************/
 
 EXTERN int wget(FAR const char *url, FAR char *buffer, int buflen,
-                wget_callback_t callback);
+                wget_callback_t callback, FAR void *arg);
 
 #undef EXTERN
 #ifdef __cplusplus
diff --git a/netutils/webclient/webclient.c b/netutils/webclient/webclient.c
index 2a2e2ddf81..3c31e6ad2f 100644
--- a/netutils/webclient/webclient.c
+++ b/netutils/webclient/webclient.c
@@ -404,7 +404,7 @@ exit:
  ****************************************************************************/
  
 int wget(FAR const char *url, FAR char *buffer, int buflen,
-         wget_callback_t callback)
+         wget_callback_t callback, FAR void *arg)
 {
   struct sockaddr_in server;
   struct wget_s ws;
@@ -559,7 +559,7 @@ int wget(FAR const char *url, FAR char *buffer, int buflen,
                 {
                   /* Let the client decide what to do with the received file */
 
-                  callback(&ws.buffer, ws.offset, ws.datend, &buflen);
+                  callback(&ws.buffer, ws.offset, ws.datend, &buflen, arg);
                 }
               else
                 {
-- 
GitLab