summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/include/ftpc.h209
-rw-r--r--apps/netutils/Makefile2
-rw-r--r--apps/netutils/ftpc/Makefile113
-rw-r--r--apps/netutils/ftpc/README.txt81
-rw-r--r--apps/netutils/ftpc/ftpc_cdup.c87
-rw-r--r--apps/netutils/ftpc/ftpc_chdir.c91
-rw-r--r--apps/netutils/ftpc/ftpc_chmod.c107
-rw-r--r--apps/netutils/ftpc/ftpc_cmd.c237
-rw-r--r--apps/netutils/ftpc/ftpc_connect.c226
-rw-r--r--apps/netutils/ftpc/ftpc_disconnect.c105
-rw-r--r--apps/netutils/ftpc/ftpc_filesize.c112
-rw-r--r--apps/netutils/ftpc/ftpc_filetime.c133
-rw-r--r--apps/netutils/ftpc/ftpc_getfile.c398
-rw-r--r--apps/netutils/ftpc/ftpc_getreply.c241
-rw-r--r--apps/netutils/ftpc/ftpc_help.c98
-rw-r--r--apps/netutils/ftpc/ftpc_idle.c121
-rw-r--r--apps/netutils/ftpc/ftpc_internal.h263
-rw-r--r--apps/netutils/ftpc/ftpc_listdir.c449
-rw-r--r--apps/netutils/ftpc/ftpc_login.c177
-rw-r--r--apps/netutils/ftpc/ftpc_mkdir.c93
-rw-r--r--apps/netutils/ftpc/ftpc_noop.c85
-rw-r--r--apps/netutils/ftpc/ftpc_putfile.c406
-rw-r--r--apps/netutils/ftpc/ftpc_pwd.c121
-rw-r--r--apps/netutils/ftpc/ftpc_quit.c92
-rw-r--r--apps/netutils/ftpc/ftpc_rename.c104
-rw-r--r--apps/netutils/ftpc/ftpc_response.c84
-rw-r--r--apps/netutils/ftpc/ftpc_rmdir.c92
-rw-r--r--apps/netutils/ftpc/ftpc_socket.c390
-rw-r--r--apps/netutils/ftpc/ftpc_transfer.c400
-rw-r--r--apps/netutils/ftpc/ftpc_unlink.c85
-rw-r--r--apps/netutils/ftpc/ftpc_utils.c251
31 files changed, 5452 insertions, 1 deletions
diff --git a/apps/include/ftpc.h b/apps/include/ftpc.h
new file mode 100644
index 000000000..77122ddae
--- /dev/null
+++ b/apps/include/ftpc.h
@@ -0,0 +1,209 @@
+/****************************************************************************
+ * apps/include/ftpc.h
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_INCLUDE_FTPC_H
+#define __APPS_INCLUDE_FTPC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <time.h>
+#include <netinet/in.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+
+#ifndef CONFIG_FTP_DEFTIMEO
+# define CONFIG_FTP_DEFTIMEO 30
+#endif
+
+#ifndef CONFIG_FTP_ANONPWD
+# define CONFIG_FTP_ANONPWD ""
+#endif
+
+#ifndef CONFIG_FTP_DEFPORT
+# define CONFIG_FTP_DEFPORT 21
+#endif
+
+#ifndef CONFIG_FTP_MAXREPLY
+# define CONFIG_FTP_MAXREPLY 21
+#endif
+
+#ifndef CONFIG_FTP_TMPDIR
+# define CONFIG_FTP_TMPDIR "/tmp"
+#endif
+
+#ifndef CONFIG_FTP_BUFSIZE
+# define CONFIG_FTP_BUFSIZE 4096
+#endif
+
+#ifndef CONFIG_FTP_MAXPATH
+# define CONFIG_FTP_MAXPATH 256
+#endif
+
+/* Interface arguments ******************************************************/
+/* These definitions describe how a put operation should be performed */
+
+#define FTPC_PUT_NORMAL 0 /* Just PUT the file on the server */
+#define FTPC_PUT_APPEND 1 /* Append file to an existing file on the server */
+#define FTPC_PUT_UNIQUE 2 /* Create a uniquely named file on the server */
+#define FTPC_PUT_RESUME 3 /* Resume a previously started PUT transfer */
+
+/* These definitions describe how a get operation should be performed */
+
+#define FTPC_GET_NORMAL 0 /* Just GET the file from the server */
+#define FTPC_GET_APPEND 1 /* Append new file to an existing file */
+#define FTPC_GET_RESUME 3 /* Resume a previously started GET transfer */
+
+/* Transfer mode encoding */
+
+#define FTPC_XFRMODE_UNKNOWN 0 /* Nothing has been transferred yet */
+#define FTPC_XFRMODE_ASCII 1 /* Last transfer was ASCII mode */
+#define FTPC_XFRMODE_BINARY 2 /* Last transfer was binary mode */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+/* This "handle" describes the FTP session */
+
+typedef FAR void *SESSION;
+
+/* This structure provides information to connect to a host FTP server */
+
+struct ftpc_connect_s
+{
+ struct in_addr addr; /* Server/proxy IP address */
+ uint16_t port; /* Server/proxy port number (usually 21) in network order */
+};
+
+/* This structure provides FTP login information */
+
+struct ftpc_login_s
+{
+ FAR const char *uname; /* Login uname */
+ FAR const char *pwd; /* Login pwd */
+ FAR const char *rdir; /* Initial remote directory */
+ bool pasv; /* true: passive connection mode */
+};
+
+/* This structure describes one simple directory listing. The directory
+ * list container as well the individual filename strings are allocated.
+ * The number of names in tha actual allocated array is variable, given
+ * by the nnames field.
+ *
+ * Since the structure and file names are allocated, they must be freed
+ * by calling ftpc_dirfree() when they are no longer needed. Allocated
+ * name strings maby be "stolen" from the array but the pointer int the
+ * array should be nullified so that the string is not freed by
+ * ftpc_dirfree().
+ */
+
+struct ftpc_dirlist_s
+{
+ unsigned int nnames; /* Number of entries in name[] array */
+ FAR char *name[1]; /* Filename with absolute path */
+};
+
+#define SIZEOF_FTPC_DIRLIST(n) \
+ (sizeof(struct ftpc_dirlist_s) + ((n)-1)*sizeof(FAR char *))
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C" {
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+/* Connection management ****************************************************/
+
+EXTERN SESSION ftpc_connect(FAR struct ftpc_connect_s *server);
+EXTERN void ftpc_disconnect(SESSION handle);
+
+/* FTP commands *************************************************************/
+
+EXTERN int ftpc_login(SESSION handle, FAR struct ftpc_login_s *login);
+EXTERN int ftpc_quit(SESSION handle);
+
+EXTERN int ftpc_chdir(SESSION handle, FAR const char *path);
+EXTERN FAR char *ftpc_pwd(SESSION handle);
+EXTERN int ftpc_cdup(SESSION handle);
+EXTERN int ftpc_mkdir(SESSION handle, FAR const char *path);
+EXTERN int ftpc_rmdir(SESSION handle, FAR const char *path);
+
+EXTERN int ftpc_unlink(SESSION handle, FAR const char *path);
+EXTERN int ftpc_chmod(SESSION handle, FAR const char *path, FAR const char *mode);
+EXTERN int ftpc_rename(SESSION handle, FAR const char *oldname, FAR const char *newname);
+EXTERN uint64_t ftpc_filesize(SESSION handle, FAR const char *path);
+EXTERN time_t ftpc_filetime(SESSION handle, FAR const char *filename);
+
+EXTERN int ftpc_idle(SESSION handle, unsigned int idletime);
+EXTERN int ftpc_noop(SESSION handle);
+EXTERN int ftpc_help(SESSION handle, FAR const char *arg);
+
+/* Director listings ********************************************************/
+
+EXTERN FAR struct ftpc_dirlist_s *ftpc_listdir(SESSION handle,
+ FAR const char *dirpath);
+EXTERN void ftpc_dirfree(FAR struct ftpc_dirlist_s *dirlist);
+
+/* File transfers ***********************************************************/
+
+EXTERN int ftpc_getfile(SESSION handle, FAR const char *rname,
+ FAR const char *lname, uint8_t how, uint8_t xfrmode);
+EXTERN int ftp_putfile(SESSION handle, FAR const char *lname,
+ FAR const char *rname, uint8_t how, uint8_t xfrmode);
+
+/* FTP response *************************************************************/
+
+EXTERN FAR char *ftpc_response(SESSION handle);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+#endif /* __APPS_INCLUDE_FTPC_H */
diff --git a/apps/netutils/Makefile b/apps/netutils/Makefile
index 91363f156..df61f97e8 100644
--- a/apps/netutils/Makefile
+++ b/apps/netutils/Makefile
@@ -38,7 +38,7 @@
# Sub-directories
ifeq ($(CONFIG_NET),y)
-SUBDIRS = uiplib dhcpc dhcpd resolv smtp telnetd webclient webserver tftpc thttpd
+SUBDIRS = uiplib dhcpc dhcpd ftpc resolv smtp telnetd webclient webserver tftpc thttpd
endif
all: nothing
diff --git a/apps/netutils/ftpc/Makefile b/apps/netutils/ftpc/Makefile
new file mode 100644
index 000000000..9c5862a53
--- /dev/null
+++ b/apps/netutils/ftpc/Makefile
@@ -0,0 +1,113 @@
+############################################################################
+# apps/netutils/ftpc/Makefile
+#
+# Copyright (C) 2011 Gregory Nutt. All rights reserved.
+# Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# 3. Neither the name NuttX nor the names of its contributors may be
+# used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+############################################################################
+
+-include $(TOPDIR)/.config
+-include $(TOPDIR)/Make.defs
+include $(APPDIR)/Make.defs
+
+# DHCP Daemn Library
+
+ASRCS =
+CSRCS =
+
+ifeq ($(CONFIG_NET_TCP),y)
+# FTP connection management
+CSRCS = ftpc_connect.c ftpc_disconnect.c
+
+# FTP commands
+CSRCS += ftpc_cdup.c ftpc_chdir.c ftpc_chmod.c ftpc_filesize.c ftpc_filetime.c
+CSRCS += ftpc_help.c ftpc_idle.c ftpc_listdir.c ftpc_login.c ftpc_mkdir.c
+CSRCS += ftpc_noop.c ftpc_pwd.c ftpc_quit.c ftpc_rename.c ftpc_rmdir.c ftpc_unlink.c
+CSRCS += ftpc_cmd.c
+
+# FTP transfers
+CSRCS += ftpc_getfile.c ftpc_putfile.c ftpc_transfer.c
+
+# FTP responses
+CSRCS += ftpc_response.c ftpc_getreply.c
+
+# FTP helpers
+CSRCS += ftpc_utils.c ftpc_socket.c
+endif
+
+AOBJS = $(ASRCS:.S=$(OBJEXT))
+COBJS = $(CSRCS:.c=$(OBJEXT))
+
+SRCS = $(ASRCS) $(CSRCS)
+OBJS = $(AOBJS) $(COBJS)
+
+ifeq ($(WINTOOL),y)
+ BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}"
+else
+ BIN = "$(APPDIR)/libapps$(LIBEXT)"
+endif
+
+ROOTDEPPATH = --dep-path .
+
+# Common build
+
+VPATH =
+
+all: .built
+.PHONY: context depend clean distclean
+
+$(AOBJS): %$(OBJEXT): %.S
+ $(call ASSEMBLE, $<, $@)
+
+$(COBJS): %$(OBJEXT): %.c
+ $(call COMPILE, $<, $@)
+
+.built: $(OBJS)
+ @( for obj in $(OBJS) ; do \
+ $(call ARCHIVE, $(BIN), $${obj}); \
+ done ; )
+ @touch .built
+
+context:
+
+.depend: Makefile $(SRCS)
+ @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep
+ @touch $@
+
+depend: .depend
+
+clean:
+ @rm -f *.o *~ .*.swp .built
+ $(call CLEAN)
+
+distclean: clean
+ @rm -f Make.dep .depend
+
+-include Make.dep
diff --git a/apps/netutils/ftpc/README.txt b/apps/netutils/ftpc/README.txt
new file mode 100644
index 000000000..d995227c7
--- /dev/null
+++ b/apps/netutils/ftpc/README.txt
@@ -0,0 +1,81 @@
+/* FTP Commands *************************************************************/
+/* Command summary:
+ *
+ * ABOR - abort a file transfer
+ * ACCT - send account information
+ * APPE - append to a remote file
+ * CDUP - CWD to the parent of the current directory
+ * CWD - change working directory
+ * DELE - delete a remote file
+ * HELP - return help on using the server
+ * LIST - list remote files
+ * MDTM - return the modification time of a file
+ * MKD - make a remote directory
+ * MLSD - Standardized directory listing (instead of LIST)
+ * MLST - Standardized object listing (instead of LIST)
+ * MODE - set transfer mode
+ * NLST - name list of remote directory
+ * NOOP - do nothing
+ * PASS - send password
+ * PASV - enter passive mode
+ * PORT - open a data port
+ * PWD - print working directory
+ * QUIT - terminate the connection
+ * REIN - reinitialize the connection
+ * RETR - retrieve a remote file
+ * REST - Sets the point at which a file transfer should start
+ * RMD - remove a remote directory
+ * RNFR - rename from
+ * RNTO - rename to
+ * SITE - site-specific commands
+ * SIZE - return the size of a file
+ * STOR - store a file on the remote host
+ * STOU - store a file uniquely
+ * STRU - set file transfer structure
+ * STAT - return server status
+ * SYST - return system type
+ * TYPE - set transfer type
+ * USER - send username
+ *
+/* FTP Replies **************************************************************/
+ *
+ * 110 - Restart marker reply.
+ * 120 - Service ready in nnn minutes.
+ * 125 - Data connection already open; transfer starting.
+ * 150 - File status okay; about to open data connection.
+ * 200 - Command okay.
+ * 202 - Command not implemented, superfluous at this site.
+ * 211 - System status, or system help reply.
+ * 212 - Directory status.
+ * 213 - File status.
+ * 214 - Help message.
+ * 215 - NAME system type.
+ * 220 - Service ready for new user.
+ * 221 - Service closing control connection.
+ * 225 - Data connection open; no transfer in progress.
+ * 226 - Closing data connection.
+ * 227 - Entering Passive Mode (h1,h2,h3,h4,p1,p2).
+ * 230 - User logged in, proceed.
+ * 250 - Requested file action okay, completed.
+ * 257 - "PATHNAME" created.
+ * 331 - User name okay, need password.
+ * 332 - Need account for login.
+ * 350 - Requested file action pending further information.
+ * 421 - Service not available, closing control connection.
+ * 425 - Can't open data connection.
+ * 426 - Connection closed; transfer aborted.
+ * 450 - Requested file action not taken.
+ * 451 - Requested action aborted: local error in processing.
+ * 452 - Requested action not taken.
+ * 500 - Syntax error, command unrecognized.
+ * 501 - Syntax error in parameters or arguments.
+ * 502 - Command not implemented.
+ * 503 - Bad sequence of commands.
+ * 504 - Command not implemented for that parameter.
+ * 530 - Not logged in.
+ * 532 - Need account for storing files.
+ * 550 - Requested action not taken.
+ * 551 - Requested action aborted: page type unknown.
+ * 552 - Requested file action aborted.
+ * 553 - Requested action not taken.
+ */
diff --git a/apps/netutils/ftpc/ftpc_cdup.c b/apps/netutils/ftpc/ftpc_cdup.c
new file mode 100644
index 000000000..323033390
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_cdup.c
@@ -0,0 +1,87 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_cdup.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_cdup
+ *
+ * Description:
+ * Make the parent of the current directory be the new current directory.
+ *
+ ****************************************************************************/
+
+ int ftpc_cdup(SESSION handle)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ int ret;
+
+ ret = ftpc_cmd(session, "CDUP");
+ ftpc_curdir(session);
+ return ret;
+}
+
diff --git a/apps/netutils/ftpc/ftpc_chdir.c b/apps/netutils/ftpc/ftpc_chdir.c
new file mode 100644
index 000000000..ddf6452c4
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_chdir.c
@@ -0,0 +1,91 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_chdir.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_chdir
+ *
+ * Description:
+ * Change the current working directory.
+ *
+ ****************************************************************************/
+
+int ftpc_chdir(SESSION handle, FAR const char *path)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ int ret;
+
+ ret = ftpc_cmd(session, "CWD %s", path);
+ if (ret != OK)
+ {
+ return ret;
+ }
+
+ ftpc_curdir(session);
+ return OK;
+}
diff --git a/apps/netutils/ftpc/ftpc_chmod.c b/apps/netutils/ftpc/ftpc_chmod.c
new file mode 100644
index 000000000..332df2b0c
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_chmod.c
@@ -0,0 +1,107 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_chmod.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <debug.h>
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_chmod
+ *
+ * Description:
+ * Change the protections on the remote file.
+ *
+ ****************************************************************************/
+
+int ftpc_chmod(SESSION handle, FAR const char *path, FAR const char *mode)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ int ret;
+
+ /* Does the server support the size CHMOD command? */
+
+ if (FTPC_HAS_CHMOD(session))
+ {
+ ret = ftpc_cmd(session, "SITE CHMOD %s %s", mode, path);
+
+ /* Check for "502 Command not implemented" */
+
+ if (session->code == 502)
+ {
+ /* No.. the server does not support the SITE CHMOD command */
+
+ FTPC_CLR_CHMOD(session);
+ }
+
+ return OK;
+ }
+ else
+ {
+ ndbg("Server does not support SITE CHMOD\n");
+ }
+
+ return ERROR;
+}
diff --git a/apps/netutils/ftpc/ftpc_cmd.c b/apps/netutils/ftpc/ftpc_cmd.c
new file mode 100644
index 000000000..240a513e8
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_cmd.c
@@ -0,0 +1,237 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_cmd.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <debug.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_restore
+ *
+ * Description:
+ * Restore the connection to the server and log in again.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_FTP_AUTORECONNECT
+static int ftpc_restore(struct ftpc_session_s *session)
+{
+ int ret;
+
+ if (session)
+ {
+ /* Set the initial directory to the last valid current directory */
+
+ free(session->initdir);
+ session->initdir = ftpc_dequote(session->curdir);
+
+ /* Reconnect to the server */
+
+ ret = ftpc_reconnect(session);
+ if (ret == 0)
+ {
+ /* Log into the server */
+
+ ret = ftpc_relogin(session);
+ }
+ else
+ {
+ /* Failed to reconnect to the server */
+
+ ftpc_reset(session);
+ }
+ return ret;
+ }
+
+ return ERROR;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_cmd
+ *
+ * Description:
+ * Send the specified command to the server.
+ *
+ ****************************************************************************/
+
+int ftpc_cmd(struct ftpc_session_s *session, const char *cmd, ...)
+{
+ va_list ap;
+#ifdef CONFIG_FTP_AUTORECONNECT
+ bool reconnect = false;
+#endif
+ int ret;
+
+ /* Verify that we are still connecte to the server */
+
+ if (!ftpc_sockconnected(&session->cmd))
+ {
+ ndbg("Cmd channel si not connected\n");
+ goto errout;
+ }
+
+ /* Loop, reconnecting as necessary until the command is sent */
+
+#ifdef CONFIG_FTP_AUTORECONNECT
+ for (;;)
+#endif
+ {
+ /* Send the command */
+
+ va_start(ap, cmd);
+ ret = ftpc_sockprintf(&session->cmd, cmd, ap);
+ if (ret >= 0)
+ {
+ ret = ftpc_sockprintf(&session->cmd, "\r\n");
+ if (ret >= 0)
+ {
+ ret = ftpc_sockflush(&session->cmd);
+ }
+ }
+ va_end(ap);
+
+ /* Check for an error in sending the data */
+
+ if (ret < 0)
+ {
+ ndbg("Error sending cmd: %s, %d\n" cmd, errno);
+ goto errout;
+ }
+
+ /* Get the response to the command */
+
+ ret = fptc_getreply(session);
+ if (ret < 0)
+ {
+ ndbg("Error getting reply: %d\n" errno);
+ goto errout;
+ }
+
+ /* Check for "421 Service not available, closing control connection" */
+
+ if (session->code == 421)
+ {
+ /* Server is closing the control connection. */
+
+ ndbg("Server closed control connection\n");
+
+ /* If we were previously logged in and this is not a QUIT commnad
+ * then attempt to automatically reconnect to the server.
+ */
+
+#ifdef CONFIG_FTP_AUTORECONNECT
+ if (ftpc_loggedin(session) && strcasecmp(cmd, "QUIT") != 0)
+ {
+ /* Don't try re-connecting more than once */
+
+ if (reconnect)
+ {
+ ndbg("Reconnect failed\n");
+ goto errout;
+ }
+ else
+ {
+ /* Try to restore the connection and, if successful,
+ * continue the loop and try to send the command again.
+ */
+
+ ndbg("Reconnecting...\n");
+ reconnect = true;
+ ret = ftpc_restore();
+ if (ret < 0)
+ {
+ ndbg("Failed to restore the connection");
+ goto errout;
+ }
+ continue;
+ }
+ }
+ else
+#endif
+ {
+ /* Don't try to connect, just return an error (retaining
+ * the session response code (421)
+ */
+
+ return ERROR;
+ }
+ }
+
+ /* The command was successfully sent */
+
+ return OK;
+ }
+
+errout:
+ session->code = -1;
+ return ERROR;
+}
diff --git a/apps/netutils/ftpc/ftpc_connect.c b/apps/netutils/ftpc/ftpc_connect.c
new file mode 100644
index 000000000..94add3d54
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_connect.c
@@ -0,0 +1,226 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_connect.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_connect
+ *
+ * Description:
+ * Create a session handle and connect to the server.
+ *
+ ****************************************************************************/
+
+SESSION ftpc_connect(FAR struct ftpc_connect_s *server)
+{
+ FAR struct ftpc_session_s *session;
+ int ret;
+
+ /* Allocate a session structure */
+
+ session = (struct ftpc_session_s *)zalloc(sizeof(struct ftpc_session_s));
+ if (!session)
+ {
+ ndbg("Failed to allocate a session\n");
+ set_errno(ENOMEM);
+ goto errout;
+ }
+
+ /* Initialize the session structure */
+
+ session->addr.s_addr = server->addr.s_addr;
+ session->port = server->port;
+
+ /* Create up a timer to prevent hangs */
+
+ session->wdog = wd_create();
+
+ /* And (Re-)connect to the server */
+
+ ret = ftpc_reconnect(session);
+ if (ret != OK)
+ {
+ ndbg("ftpc_reconnect() failed: %d\n", errno);
+ goto errout_with_alloc;
+ }
+ return (SESSION)session;
+
+errout_with_alloc:
+ free(session);
+errout:
+ return NULL;
+}
+
+/****************************************************************************
+ * Name: ftpc_reconnect
+ *
+ * Description:
+ * re-connect to the server either initially, or after loss of connection.
+ *
+ ****************************************************************************/
+
+int ftpc_reconnect(FAR struct ftpc_session_s *session)
+{
+ struct sockaddr_in addr;
+#ifdef CONFIG_DEBUG
+ char *tmp;
+#endif
+ int ret;
+
+ /* Re-initialize the session structure */
+
+ session->replytimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC;
+ session->conntimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC;
+ session->xfrmode = FTPC_XFRMODE_UNKNOWN;
+
+ /* Set up a timer to prevent hangs */
+
+ ret = wd_start(session->wdog, session->conntimeo, ftpc_conntimeo, 1, session);
+ if (ret != OK)
+ {
+ ndbg("wd_start() failed\n");
+ goto errout;
+ }
+
+ /* Initialize a socket */
+
+ ret = ftpc_sockinit(&session->cmd);
+ if (ret != OK)
+ {
+ ndbg("ftpc_sockinit() failed: %d\n", errno);
+ goto errout;
+ }
+
+ /* Connect the socket to the server */
+
+#ifdef CONFIG_DEBUG
+ tmp = inet_ntoa(session->addr);
+ ndbg("Connecting to server address %s:%d\n",
+ server->proxy ? "proxy" : "server", tmp, ntohl(session->port));
+ free(tmp);
+#endif
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = session->port;
+ addr.sin_addr.s_addr = session->addr.s_addr;
+ ret = ftpc_sockconnect(&session->cmd, &addr);
+ if (ret != OK)
+ {
+ ndbg("ftpc_sockconnect() failed: %d\n", errno);
+ goto errout_with_socket;
+ }
+
+ /* Read startup message from server */
+
+ fptc_getreply(session);
+
+ /* Check for "120 Service ready in nnn minutes" */
+
+ if (session->code == 120)
+ {
+ fptc_getreply(session);
+ }
+ wd_cancel(session->wdog);
+
+ if (!ftpc_sockconnected(&session->cmd))
+ {
+ ftpc_reset(session);
+ goto errout;
+ }
+
+ /* Check for "220 Service ready for new user" */
+
+ if (session->code == 220)
+ {
+ FTPC_SET_CONNECTED(session);
+ }
+
+ if (!FTPC_IS_CONNECTED(session))
+ {
+ goto errout_with_socket;
+ }
+
+#ifdef CONFIG_DEBUG
+ ndbg("Connected\n");
+ tmp = inet_ntoa(session->cmd.raddr.sin_addr.s_addr);
+ ndbg(" Remote address: %s:%d\n", tmp, ntohl(session->cmd.raddr.sin_port));
+ free(tmp);
+ tmp = inet_ntoa(session->cmd.laddr.sin_addr.s_addr);
+ ndbg(" Local address: %s:d\n", tmp, ntohl(session->cmd.laddr.sin_port));
+ free(tmp);
+#endif
+ return OK;
+
+errout_with_socket:
+ ftpc_sockclose(&session->cmd);
+errout:
+ return ERROR;
+}
diff --git a/apps/netutils/ftpc/ftpc_disconnect.c b/apps/netutils/ftpc/ftpc_disconnect.c
new file mode 100644
index 000000000..e55c35e34
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_disconnect.c
@@ -0,0 +1,105 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_disconnect.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdlib.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_disconnect
+ *
+ * Description:
+ * Disconnect from the server and destroy the session handle..
+ *
+ ****************************************************************************/
+
+void ftpc_disconnect(SESSION handle)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ if (session)
+ {
+ /* Release sockets */
+
+ ftpc_sockclose(&session->data);
+ ftpc_sockclose(&session->cmd);
+
+ /* Free strings */
+
+ free(session->uname);
+ free(session->pwd);
+ free(session->initdir);
+ free(session->homedir);
+ free(session->curdir);
+ free(session->prevdir);
+ free(session->rname);
+ free(session->lname);
+
+ /* Then destroy the session */
+
+ free(session);
+ }
+}
diff --git a/apps/netutils/ftpc/ftpc_filesize.c b/apps/netutils/ftpc/ftpc_filesize.c
new file mode 100644
index 000000000..afd773e41
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_filesize.c
@@ -0,0 +1,112 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_filesize.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_filesize
+ *
+ * Description:
+ * Return the size of the given file on the remote server.
+ *
+ ****************************************************************************/
+
+ uint64_t ftpc_filesize(SESSION handle, FAR const char *path)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ uint64_t ret;
+
+ /* Check if the host supports the SIZE command */
+
+ if (!FTPC_HAS_SIZE(session))
+ {
+ return ERROR;
+ }
+
+ if (ftpc_xfrmode(session, FTPC_XFRMODE_ASCII) != 0)
+ {
+ return ERROR;
+ }
+
+ ret = ftpc_cmd(session, "SIZE %s", path);
+
+ /* Check for "502 Command not implemented" */
+
+ if (session->code == 502)
+ {
+ /* No.. the host does not support the SIZE command */
+
+ FTPC_CLR_SIZE(session);
+ return ERROR;
+ }
+
+ sscanf(session->reply, "%*s %llu", &ret);
+ return ret;
+}
diff --git a/apps/netutils/ftpc/ftpc_filetime.c b/apps/netutils/ftpc/ftpc_filetime.c
new file mode 100644
index 000000000..331e7e7b6
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_filetime.c
@@ -0,0 +1,133 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_filetime.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <string.h>
+#include <time.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_filetime
+ *
+ * Descripton:
+ * Return the timestamp on the remote file.
+ *
+ ****************************************************************************/
+
+time_t ftpc_filetime(SESSION handle, FAR const char *filename)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ struct tm timestamp;
+ int ret;
+
+ /* Make sure that the server is still connected */
+
+ if (!ftpc_connected(session))
+ {
+ return ERROR;
+ }
+
+ /* Does the server support the MDTM command? */
+
+ if (!FTPC_HAS_MDTM(session))
+ {
+ return ERROR;
+ }
+
+ /* Get the file time in UTC */
+
+ memset(&timestamp, 0, sizeof(timestamp));
+ ret = ftpc_cmd(session, "MDTM %s", filename);
+ if (ret != OK)
+ {
+ return ERROR;
+ }
+
+ /* Check for "202 Command not implemented, superfluous at this site" */
+
+ if (session->code == 202)
+ {
+ FTPC_CLR_MDTM(session);
+ return ERROR;
+ }
+
+ /* Check for "213 File status" */
+
+ if (session->code != 213)
+ {
+ return ERROR;
+ }
+
+ /* Time is Universal Coordinated Time */
+
+ sscanf(session->reply, "%*s %04d%02d%02d%02d%02d%02d",
+ &timestamp.tm_year, &timestamp.tm_mon, &timestamp.tm_mday,
+ &timestamp.tm_hour, &timestamp.tm_min, &timestamp.tm_sec);
+ timestamp.tm_year -= 1900;
+ timestamp.tm_mon--;
+ return mktime(&timestamp);
+}
diff --git a/apps/netutils/ftpc/ftpc_getfile.c b/apps/netutils/ftpc/ftpc_getfile.c
new file mode 100644
index 000000000..a3ea5008d
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_getfile.c
@@ -0,0 +1,398 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_getfile.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_recvinit
+ *
+ * Description:
+ * Initialize to receive a file
+ *
+ ****************************************************************************/
+
+static int ftpc_recvinit(struct ftpc_session_s *session, FAR const char *path,
+ uint8_t xfrmode, off_t offset)
+{
+ int ret;
+
+ /* Reset transfer related variables */
+
+ ftpc_xfrreset(session);
+
+ ret = ftpc_xfrinit(session);
+ if (ret != OK)
+ {
+ return ERROR;
+ }
+
+ /* Configure the transfer: Initial file offset and tranfer mode */
+
+ session->offset = 0;
+ session->filesize = -1;
+ ftpc_xfrmode(session, xfrmode);
+
+ /* Handle the resume offset (caller is responsible for fseeking in the
+ * file)
+ */
+
+ if (offset > 0)
+ {
+ /* Send the REST command. This command sets the offset where the
+ * transfer should start. This must come after PORT or PASV commands.
+ */
+
+ ret = ftpc_cmd(session, "REST %ld", offset);
+ if (ret < 0)
+ {
+ ndbg("REST command failed: %d\n", errno);
+ return ERROR;
+ }
+
+ session->size = offset;
+ session->rstrsize = offset;
+ }
+
+ /* Send the RETR (Retrieve a remote file) command */
+
+ ret = ftpc_cmd(session, "RETR %s", path);
+ if (ret < 0)
+ {
+ ndbg("RETR command failed: %d\n", errno);
+ return ERROR;
+ }
+
+ /* Accept a connection on the data socket */
+
+ ret = ftpc_sockaccept(&session->data, "r", FTPC_IS_PASSIVE(session));
+ if (ret != OK)
+ {
+ ndbg("data connection not accepted\n");
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpc_waitinput
+ *
+ * Description:
+ * Wait to receive data.
+ *
+ ****************************************************************************/
+
+static int ftpc_waitinput(FAR struct ftpc_session_s *session)
+{
+ int ret;
+ do {
+ ret = ftpc_waitdata(session, session->data.instream, true);
+ if (ret == -1) {
+ if (errno == EINTR)
+ {
+ FTPC_SET_INTERRUPT(session);
+ }
+ return ERROR;
+ }
+ } while(ret == 0);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ftpc_recvbinary
+ *
+ * Description:
+ * Receive a binary file.
+ *
+ ****************************************************************************/
+
+static int ftpc_recvbinary(FAR struct ftpc_session_s *session,
+ FAR FILE *rinstream, FAR FILE *loutstream)
+{
+ FAR char *buf;
+ ssize_t nread;
+ ssize_t nwritten;
+ int err;
+ int ret = OK;
+
+ buf = (FAR char *)malloc(CONFIG_FTP_BUFSIZE);
+ if (!buf)
+ {
+ err = ENOMEM;
+ goto errout_with_err;
+ }
+
+ while (!feof(rinstream))
+ {
+ if (ftpc_waitinput(session) != 0)
+ {
+ nvdbg("ftpc_waitinput() failed\n");
+ err = EIO;
+ goto errout_with_buf;
+ }
+
+ nread = fread(buf, sizeof(char), CONFIG_FTP_BUFSIZE, rinstream);
+ if (nread <= 0)
+ {
+ (void)ftpc_xfrabort(session, rinstream);
+ ret = ERROR;
+ break;
+ }
+
+ nwritten = fwrite(buf, sizeof(char), nread, loutstream);
+ if (nwritten != nread)
+ {
+ (void)ftpc_xfrabort(session, loutstream);
+ ret = ERROR;
+ break;
+ }
+
+ session->size += nread;
+ }
+
+ free(buf);
+ return ret;
+
+errout_with_buf:
+ free(buf);
+errout_with_err:
+ set_errno(err);
+ return ERROR;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_getfile
+ *
+ * Description:
+ * Get a file from the remote host.
+ *
+ ****************************************************************************/
+
+int ftpc_getfile(SESSION handle, FAR const char *rname, FAR const char *lname,
+ uint8_t how, uint8_t xfrmode)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ struct stat statbuf;
+ FILE *loutstream;
+ off_t offset;
+ int ret;
+
+ /* Get information about the local file */
+
+ ret = stat(lname, &statbuf);
+ if (ret == 0)
+ {
+ /* It already exists. Is it a directory? */
+
+ if (S_ISDIR(statbuf.st_mode))
+ {
+ ndbg("'%s' is a directory\n", lname);
+ return ERROR;
+ }
+ }
+
+ /* Is it write-able? */
+
+#ifdef S_IWRITE
+ if (!(statbuf.st_mode & S_IWRITE))
+ {
+ ndbg("'%s' permission denied\n", lname);
+ return ERROR;
+ }
+#endif
+
+ /* Are we resuming the transfers? Is so then the starting offset is the
+ * size of the existing, partial file.
+ */
+
+ if (how == FTPC_GET_RESUME)
+ {
+ offset = statbuf.st_size;
+ }
+ else
+ {
+ offset = 0;
+ }
+
+ /* Setup to receive the file */
+
+ ret = ftpc_recvinit(session, rname, xfrmode, offset);
+ if (ret != OK)
+ {
+ ndbg("ftpc_recvinit failed\n");
+ return ERROR;
+ }
+
+ loutstream = fopen(lname, (offset > 0 || (how == FTPC_GET_APPEND)) ? "a" : "w");
+ if (!loutstream)
+ {
+ ndbg("fopen failed: %d\n", errno);
+ session->offset = 0;
+ return ERROR;
+ }
+
+ if (offset > 0)
+ {
+ ret = fseek(loutstream, offset, SEEK_SET);
+ if (ret != OK)
+ {
+ ndbg("fseek failed: %d\n", errno);
+ fclose(loutstream);
+ session->offset = 0;
+ return ERROR;
+ }
+ }
+
+ /* Save the new local and remote file names */
+
+ free(session->rname);
+ free(session->lname);
+ session->rname = strdup(rname);
+ session->lname = strdup(lname);
+
+ /* And receive the new file data */
+
+ if (xfrmode == FTPC_XFRMODE_ASCII)
+ {
+ ret = ftpc_recvbinary(session, session->data.instream, loutstream);
+ }
+ else
+ {
+ ret = ftpc_recvtext(session, session->data.instream, loutstream);
+ }
+
+ ftpc_sockclose(&session->data);
+
+ if (ret == 0)
+ {
+ fptc_getreply(session);
+ }
+
+ fclose(loutstream);
+ return (ret == OK && !FTPC_INTERRUPTED(session)) ? OK : ERROR;
+}
+
+/****************************************************************************
+ * Name: ftpc_recvbinary
+ *
+ * Description:
+ * Receive a text file.
+ *
+ ****************************************************************************/
+
+int ftpc_recvtext(FAR struct ftpc_session_s *session,
+ FAR FILE *rinstream, FAR FILE *loutstream)
+{
+ char *buf = (char *)malloc(CONFIG_FTP_BUFSIZE);
+ int c;
+ int ret = OK;
+
+ while((c = fgetc(rinstream)) != EOF) {
+
+ if (ftpc_waitinput(session) != 0)
+ {
+ break;
+ }
+
+ if (c == '\r')
+ {
+ c = fgetc(rinstream);
+ if (c == EOF)
+ {
+ (void)ftpc_xfrabort(session, rinstream);
+ ret = ERROR;
+ break;
+ }
+ if (c != '\n')
+ {
+ ungetc(c, rinstream);
+ c = '\r';
+ }
+ }
+
+ if (fputc(c, loutstream) == EOF)
+ {
+ (void)ftpc_xfrabort(session, loutstream);
+ ret = ERROR;
+ break;
+ }
+
+ session->size++;
+ }
+
+ free(buf);
+ return ret;
+}
+
+
diff --git a/apps/netutils/ftpc/ftpc_getreply.c b/apps/netutils/ftpc/ftpc_getreply.c
new file mode 100644
index 000000000..86f1c7bfa
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_getreply.c
@@ -0,0 +1,241 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_getreply.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <debug.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_gets
+ ****************************************************************************/
+
+static int ftpc_gets(struct ftpc_session_s *session)
+{
+ int ch;
+ int i = 0;
+
+ /* Start wth an empty response string */
+
+ session->reply[0] = '\0';
+
+ /* Verify that the command channel is still connected */
+
+ if (!ftpc_sockconnected(&session->cmd))
+ {
+ ndbg("Cmd channel disconnected\n");
+ return ERROR;
+ }
+
+ /* Loop until the full line is obtained */
+
+ for (;;)
+ {
+ /* Get the next character from incoming command stream */
+
+ ch = ftpc_sockgetc(&session->cmd);
+ if (ch == EOF)
+ {
+ ndbg("EOF: Server closed command stream\n");
+ ftpc_reset(session);
+ return ERROR;
+ }
+ else if (ch == TELNET_IAC)
+ {
+ /* Handle TELNET commands */
+
+ switch(ch = ftpc_sockgetc(&session->cmd))
+ {
+ case TELNET_WILL:
+ case TELNET_WONT:
+ ch = ftpc_sockgetc(&session->cmd);
+ ftpc_sockprintf(&session->cmd, "%c%c%c", TELNET_IAC, TELNET_DONT, ch);
+ ftpc_sockflush(&session->cmd);
+ break;
+
+ case TELNET_DO:
+ case TELNET_DONT:
+ ch = ftpc_sockgetc(&session->cmd);
+ ftpc_sockprintf(&session->cmd, "%c%c%c", TELNET_IAC, TELNET_WONT, ch);
+ ftpc_sockflush(&session->cmd);
+ break;
+
+ default:
+ break;
+ }
+
+ continue;
+ }
+ else if (ch == ISO_cr)
+ {
+ ch = ftpc_sockgetc(&session->cmd);
+ if (ch == '\0')
+ {
+ ch = ISO_cr;
+ }
+ else if (ch == ISO_nl)
+ {
+ session->reply[i++] = (char)ch;
+ break;
+ }
+ else if (ch != EOF)
+ {
+ /* TELNET protocol */
+
+ ungetc(ch, session->cmd.instream);
+ continue;
+ }
+ }
+ else if (ch == ISO_nl)
+ {
+ /* The ISO newline character terminates the string. Just break
+ * out of the loop.
+ */
+
+ break;
+ }
+
+ if (i < CONFIG_FTP_MAXREPLY)
+ {
+ session->reply[i++] = (char)ch;
+ }
+
+ if (i >= CONFIG_FTP_MAXREPLY)
+ {
+ ndbg("Reply truncated\n");
+ i = CONFIG_FTP_MAXREPLY;
+ }
+ }
+
+ session->reply[i] = '\0';
+ session->code = atoi(session->reply);
+ ftpc_stripcrlf(session->reply);
+ return session->code;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_getreply
+ ****************************************************************************/
+
+int fptc_getreply(struct ftpc_session_s *session)
+{
+ char tmp[5]="xxx ";
+ int ret;
+
+ /* Set up a timeout */
+
+ if (session->replytimeo)
+ {
+ ret = wd_start(session->wdog, session->replytimeo, ftpc_replytimeo, 1, session);
+ }
+
+ /* Get the next line from the server */
+
+ ret = ftpc_gets(session);
+
+ /* Do we still have a connection? */
+
+ if (!ftpc_sockconnected(&session->cmd))
+ {
+ /* No.. cancel the timer and return an error */
+
+ wd_cancel(session->wdog);
+ nvdbg("Lost connection\n");
+ return ERROR;
+ }
+
+ /* Did an error occur? */
+
+ if (ret < 0)
+ {
+ /* No.. cancel the timer and return an error */
+
+ wd_cancel(session->wdog);
+ nvdbg("ftpc_gets failed\n");
+ return ERROR;
+ }
+
+ nvdbg("Reply: %s\n", session->reply);
+
+ if (session->reply[3] == '-')
+ {
+ /* Multi-line response */
+
+ strncpy(tmp, session->reply, 3);
+ do
+ {
+ if (ftpc_gets(session) == -1)
+ {
+ break;
+ }
+
+ nvdbg("Reply: %s\n", session->reply);
+ } while(strncmp(tmp, session->reply, 4) != 0);
+ }
+
+ wd_cancel(session->wdog);
+ return ret;
+}
diff --git a/apps/netutils/ftpc/ftpc_help.c b/apps/netutils/ftpc/ftpc_help.c
new file mode 100644
index 000000000..2501ca365
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_help.c
@@ -0,0 +1,98 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_help.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_help
+ *
+ * Description:
+ * Request a list of available help commands. This implementation is
+ * fragementary and no ready for any real use at this time.
+ *
+ ****************************************************************************/
+
+int ftpc_help(SESSION handle, FAR const char *arg)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ int ret;
+
+ /* Send the HELP command with or without an argument */
+
+ if (arg)
+ {
+ ret = ftpc_cmd(session, "HELP %s", arg);
+ }
+ else
+ {
+ ret = ftpc_cmd(session, "HELP");
+ }
+
+ /* Logic is missing here to return the help string to the caller */
+
+ return ret;
+}
diff --git a/apps/netutils/ftpc/ftpc_idle.c b/apps/netutils/ftpc/ftpc_idle.c
new file mode 100644
index 000000000..945ca8577
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_idle.c
@@ -0,0 +1,121 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_idle.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <debug.h>
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_idle
+ *
+ * Description:
+ * This command will change the FTP server's idle time limit with the site
+ * idle ftp command. This is useful if the default time limit is too short
+ * for the transmission of files).
+ *
+ ****************************************************************************/
+
+int ftpc_idle(SESSION handle, unsigned int idletime)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ int ret = OK;
+
+ /* Check if the server supports the SITE IDLE command */
+
+ if (!FTPC_HAS_IDLE(session))
+ {
+ ndbg("Server doesn't support SITE IDLE\n");
+ return ERROR;
+ }
+
+ /* Did the caller provide an IDLE time? Or is this just a query for the
+ * current IDLE time setting?
+ */
+
+ if (idletime)
+ {
+ ret = ftpc_cmd(session, "SITE IDLE %u", idletime);
+ }
+ else
+ {
+ ret = ftpc_cmd(session, "SITE IDLE");
+ }
+
+ /* Check for "502 Command not implemented" */
+
+ if (session->code == 502)
+ {
+ /* Server does not support SITE IDLE */
+
+ FTPC_CLR_IDLE(session);
+ }
+
+ return ret;
+}
diff --git a/apps/netutils/ftpc/ftpc_internal.h b/apps/netutils/ftpc/ftpc_internal.h
new file mode 100644
index 000000000..4982e1f20
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_internal.h
@@ -0,0 +1,263 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_internal.h
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_NETUTILS_FTPC_FTPC_INTERNAL_H
+#define __APPS_NETUTILS_FTPC_FTPC_INTERNAL_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <time.h>
+#include <wdog.h>
+
+#include <apps/ftpc.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* MISC definitions *********************************************************/
+
+#define ISO_nl 0x0a
+#define ISO_cr 0x0d
+
+/* Telnet-related definitions */
+
+#define TELNET_DM 242
+#define TELNET_IP 244
+#define TELNET_IAC 255
+#define TELNET_WILL 251
+#define TELNET_WONT 252
+#define TELNET_DO 253
+#define TELNET_DONT 254
+
+/* Session flag bits ********************************************************/
+
+#define FTPC_FLAG_CONNECTED (1 << 0) /* Connected to host */
+#define FTPC_FLAG_LOGGEDIN (1 << 1) /* Logged in to host */
+#define FTPC_STATE_FLAGS (0x0003) /* State of connection */
+
+#define FTPC_FLAG_MDTM (1 << 2) /* Host supports MDTM command */
+#define FTPC_FLAG_SIZE (1 << 3) /* Host supports SIZE command */
+#define FTPC_FLAG_PASV (1 << 4) /* Host supports PASV command */
+#define FTPC_FLAG_STOU (1 << 5) /* Host supports STOU command */
+#define FTPC_FLAG_CHMOD (1 << 6) /* Host supports SITE CHMOD command */
+#define FTPC_FLAG_IDLE (1 << 7) /* Host supports SITE IDLE command */
+#define FTPC_HOSTCAP_FLAGS (0x00fc) /* Host capabilities */
+
+#define FTPC_FLAG_INTERRUPT (1 << 8) /* Transfer interrupted */
+#define FTPC_FLAG_PUT (1 << 9) /* Transfer is a PUT operation (upload) */
+#define FTPC_FLAG_PASSIVE (1 << 10) /* Passive mode requested */
+#define FTPC_XFER_FLAGS (0x0700) /* Transfer related */
+
+#define FTPC_FLAGS_INIT FTPC_HOSTCAP_FLAGS
+
+#define FTPC_SET_CONNECTED(s) do { (s)->flags |= FTPC_FLAG_CONNECTED; } while (0)
+#define FTPC_SET_LOGGEDIN(s) do { (s)->flags |= FTPC_FLAG_LOGGEDIN; } while (0)
+#define FTPC_SET_MDTM(s) do { (s)->flags |= FTPC_FLAG_MDTM; } while (0)
+#define FTPC_SET_SIZE(s) do { (s)->flags |= FTPC_FLAG_SIZE; } while (0)
+#define FTPC_SET_PASV(s) do { (s)->flags |= FTPC_FLAG_PASV; } while (0)
+#define FTPC_SET_STOU(s) do { (s)->flags |= FTPC_FLAG_STOU; } while (0)
+#define FTPC_SET_CHMOD(s) do { (s)->flags |= FTPC_FLAG_CHMOD; } while (0)
+#define FTPC_SET_IDLE(s) do { (s)->flags |= FTPC_FLAG_IDLE; } while (0)
+#define FTPC_SET_INTERRUPT(s) do { (s)->flags |= FTPC_FLAG_INTERRUPT; } while (0)
+#define FTPC_SET_PUT(s) do { (s)->flags |= FTPC_FLAG_PUT; } while (0)
+#define FTPC_SET_PASSIVE(s) do { (s)->flags |= FTPC_FLAG_PASSIVE; } while (0)
+
+#define FTPC_CLR_CONNECTED(s) do { (s)->flags &= ~FTPC_FLAG_CONNECTED; } while (0)
+#define FTPC_CLR_LOGGEDIN(s) do { (s)->flags &= ~FTPC_FLAG_LOGGEDIN; } while (0)
+#define FTPC_CLR_MDTM(s) do { (s)->flags &= ~FTPC_FLAG_MDTM; } while (0)
+#define FTPC_CLR_SIZE(s) do { (s)->flags &= ~FTPC_FLAG_SIZE; } while (0)
+#define FTPC_CLR_PASV(s) do { (s)->flags &= ~FTPC_FLAG_PASV; } while (0)
+#define FTPC_CLR_STOU(s) do { (s)->flags &= ~FTPC_FLAG_STOU; } while (0)
+#define FTPC_CLR_CHMOD(s) do { (s)->flags &= ~FTPC_FLAG_CHMOD; } while (0)
+#define FTPC_CLR_IDLE(s) do { (s)->flags &= ~FTPC_FLAG_IDLE; } while (0)
+#define FTPC_CLR_INTERRUPT(s) do { (s)->flags &= ~FTPC_FLAG_INTERRUPT; } while (0)
+#define FTPC_CLR_PUT(s) do { (s)->flags &= ~FTPC_FLAG_PUT; } while (0)
+#define FTPC_CLR_PASSIVE(s) do { (s)->flags &= ~FTPC_FLAG_PASSIVE; } while (0)
+
+#define FTPC_IS_CONNECTED(s) (((s)->flags & FTPC_FLAG_CONNECTED) != 0)
+#define FTPC_IS_LOGGEDIN(s) (((s)->flags & FTPC_FLAG_LOGGEDIN) != 0)
+#define FTPC_HAS_MDTM(s) (((s)->flags & FTPC_FLAG_MDTM) != 0)
+#define FTPC_HAS_SIZE(s) (((s)->flags & FTPC_FLAG_SIZE) != 0)
+#define FTPC_HAS_PASV(s) (((s)->flags & FTPC_FLAG_PASV) != 0)
+#define FTPC_HAS_STOU(s) (((s)->flags & FTPC_FLAG_STOU) != 0)
+#define FTPC_HAS_CHMOD(s) (((s)->flags & FTPC_FLAG_CHMOD) != 0)
+#define FTPC_HAS_IDLE(s) (((s)->flags & FTPC_FLAG_IDLE) != 0)
+#define FTPC_INTERRUPTED(s) (((s)->flags & FTPC_FLAG_INTERRUPT) != 0)
+#define FTPC_IS_PUT(s) (((s)->flags & FTPC_FLAG_PUT) != 0)
+#define FTPC_IS_PASSIVE(s) (((s)->flags & FTPC_FLAG_PASSIVE) != 0)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* This structure represents the state of one socket connection */
+
+struct ftpc_socket_s
+{
+ int sd; /* Socket descriptor */
+ FILE *instream; /* Incoming stream */
+ FILE *outstream; /* Outgoing stream */
+ struct sockaddr_in laddr; /* Local address */
+ struct sockaddr_in raddr; /* Remote address */
+ bool connected; /* True: socket is connected */
+};
+
+/* This structure represents the state of an FTP connection */
+
+struct ftpc_session_s
+{
+ struct in_addr addr; /* Server/proxy IP address */
+ struct ftpc_socket_s cmd; /* FTP command channel */
+ struct ftpc_socket_s data; /* FTP data channel */
+ WDOG_ID wdog; /* Timer */
+ FAR char *uname; /* Login uname */
+ FAR char *pwd; /* Login pwd */
+ FAR char *initdir; /* Initial remote directory */
+ FAR char *homedir; /* Home directory (curdir on startup) */
+ FAR char *curdir; /* Current directory */
+ FAR char *prevdir; /* Previous directory */
+ FAR char *rname; /* Remote file name */
+ FAR char *lname; /* Local file name */
+ uint8_t xfrmode; /* Previous data transfer type (See FTPC_XFRMODE_* defines) */
+ uint16_t port; /* Server/proxy port number (probably 21) */
+ uint16_t flags; /* Connection flags (see FTPC_FLAGS_* defines) */
+ uint16_t code; /* Last 3-digit replay code */
+ uint32_t replytimeo; /* Server replay timeout (ticks) */
+ uint32_t conntimeo; /* Connection timeout (ticks) */
+ off_t filesize; /* Total file size to transfer */
+ off_t offset; /* Transfer file offset */
+ off_t size; /* Number of bytes transferred */
+ off_t rstrsize; /* restart size */
+
+ char reply[CONFIG_FTP_MAXREPLY+1]; /* Last reply string from server */
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C" {
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Inline Functions/Function-like Macros
+ ****************************************************************************/
+
+#define ftpc_sockconnected(s) \
+ ((s) && (s)->connected)
+#define ftpc_connected(s) \
+ (FTPC_IS_CONNECTED(session) && ftpc_sockconnected(&session->cmd))
+#define ftpc_loggedin(s) \
+ (ftpc_connected(s) && FTPC_IS_LOGGEDIN(s))
+
+#define ftpc_sockgetc(s) \
+ fgetc((s)->instream)
+#define ftpc_sockflush(s) \
+ fflush((s)->outstream)
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+/* Low-level string management */
+
+EXTERN void ftpc_stripcrlf(FAR char *str);
+EXTERN void ftpc_stripslash(FAR const char *str);
+EXTERN FAR char *ftpc_dequote(FAR const char *hostname);
+
+/* FTP helpers */
+
+EXTERN void ftpc_reset(struct ftpc_session_s *session);
+EXTERN int ftpc_cmd(struct ftpc_session_s *session, const char *cmd, ...);
+EXTERN int fptc_getreply(struct ftpc_session_s *session);
+EXTERN void ftpc_curdir(struct ftpc_session_s *session);
+EXTERN int ftpc_xfrmode(struct ftpc_session_s *session, uint8_t xfrmode);
+
+EXTERN int ftpc_reconnect(FAR struct ftpc_session_s *session);
+EXTERN int ftpc_relogin(FAR struct ftpc_session_s *session);
+
+/* Socket helpers */
+
+EXTERN int ftpc_sockinit(FAR struct ftpc_socket_s *sock);
+EXTERN void ftpc_sockclose(FAR struct ftpc_socket_s *sock);
+EXTERN int ftpc_sockconnect(FAR struct ftpc_socket_s *sock,
+ FAR struct sockaddr_in *addr);
+EXTERN int ftpc_sockgetsockname(FAR struct ftpc_socket_s *sock,
+ FAR struct sockaddr_in *sa);
+EXTERN int ftpc_sockaccept(FAR struct ftpc_socket_s *sock,
+ FAR const char *mode, bool passive);
+EXTERN int ftpc_socklisten(FAR struct ftpc_socket_s *sock);
+EXTERN void ftpc_sockcopy(FAR struct ftpc_socket_s *dest,
+ FAR const struct ftpc_socket_s *src);
+
+/* Socket I/O helpers */
+
+EXTERN int ftpc_sockprintf(FAR struct ftpc_socket_s *sock, const char *str, ...);
+
+/* Timeout handlers */
+
+EXTERN void ftpc_replytimeo(int argc, uint32_t arg1, ...);
+EXTERN void ftpc_conntimeo(int argc, uint32_t arg1, ...);
+
+/* Transfer helpers */
+
+EXTERN int ftpc_xfrinit(FAR struct ftpc_session_s *session);
+EXTERN int ftpc_recvtext(FAR struct ftpc_session_s *session,
+ FAR FILE *rinstream, FAR FILE *loutstream);
+EXTERN int ftpc_waitdata(FAR struct ftpc_session_s *session,
+ FAR FILE *stream, bool rdwait);
+
+EXTERN void ftpc_xfrreset(struct ftpc_session_s *session);
+EXTERN int ftpc_xfrabort(FAR struct ftpc_session_s *session,
+ FAR FILE *stream);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+#endif /* __APPS_NETUTILS_FTPC_FTPC_INTERNAL_H */
diff --git a/apps/netutils/ftpc/ftpc_listdir.c b/apps/netutils/ftpc/ftpc_listdir.c
new file mode 100644
index 000000000..2b7706fc1
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_listdir.c
@@ -0,0 +1,449 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_listdir.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <libgen.h>
+#include <debug.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+typedef void (*callback_t)(FAR const char *name, FAR void *arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_abspath
+ *
+ * Description:
+ * Get the absolute path to a file, handling tilde expansion.
+ *
+ ****************************************************************************/
+
+static FAR char *ftpc_abspath(FAR struct ftpc_session_s *session,
+ FAR const char *relpath);
+{
+ FAR char *ptr = NULL;
+ int ret = OK;
+
+ /* If no relative path was provide, then use the current working directory */
+
+ if (!relpath)
+ {
+ return strdup(session->curdir);
+ }
+
+ /* Handle tilde expansion */
+
+ if (relpath[0] == '~')
+ {
+ /* Is the relative path only '~' */
+
+ if (relpath[1] == '\0')
+ {
+ return strdup(session->home);
+ }
+
+ /* No... then a '/' better follow the tilde */
+
+ else if (relpath[1] == '/')
+ {
+ ret = asprintf(&ptr, "%s%s", session->homedir, &relpath[1]);
+ }
+
+ /* Hmmm... this prety much guaranteed to fail */
+
+ else
+ {
+ ptr = strdup(relpath);
+ }
+ }
+
+ /* No tilde expansion. Check for a path relative to the current
+ * directory.
+ */
+
+ else if (strncmp(relpath, "./", 2) == 0)
+ {
+ ret = asprintf(&ptr, "%s%s", session->curdir, relpath+1);
+ }
+
+ /* Check for an absolute path */
+
+ else if (relpath[0] == '/' && relpath[1] == ':' && relpath[2] == '\\')
+ {
+ ptr = strdup(relpath);
+ }
+
+ /* Take a wild guess */
+
+ else
+ {
+ ret = asprintf(&ptr, "%s/%s", session->curdir, relpath);
+ }
+
+ return ptr;
+}
+
+/****************************************************************************
+ * Name: ftpc_dircount
+ *
+ * Description:
+ * This callback simply counts the number of names in the directory.
+ *
+ ****************************************************************************/
+
+static void ftpc_dircount(FAR const char *name, FAR void *arg)
+{
+ unsigned int *dircount = (unsigned int *)arg;
+ (*dircount)++;
+}
+
+/****************************************************************************
+ * Name: ftpc_addname
+ *
+ * Description:
+ * This callback adds a name to the directory listing.
+ *
+ ****************************************************************************/
+
+static void ftpc_addname(FAR const char *name, FAR void *arg)
+{
+ FAR struct ftpc_dirlist_s *dirlist = (FAR struct ftpc_dirlist_s *)arg;
+ unsigned int nnames = dirlist->nnames;
+ dirlist->name[nnames] = strdup(name);
+ dirlist->nnames = nnames + 1;
+}
+
+/****************************************************************************
+ * Name: ftpc_nlstparse
+ *
+ * Description:
+ * Parse the NLST directory response. The NLST response consists of a
+ * sequence of pathnames. Each pathname is terminated by \r\n.
+ *
+ * If a pathname starts with a slash, it represents the pathname. If a
+ * pathname does not start with a slash, it represents the pathname obtained
+ * by concatenating the pathname of the directory and the pathname.
+ *
+ * IF NLST of directory /pub produces foo\r\nbar\r\n, it refers to the
+ * pathnames /pub/foo and /pub/bar.
+ *
+ ****************************************************************************/
+
+static void ftpc_nlstparse(FAR FILE *instream, callback_t callback,
+ FAR void *arg)
+{
+ char buffer[CONFIG_FTP_MAXPATH+1];
+
+ /* Read every filename from the temporary file */
+
+ while (!feof(instream))
+ {
+ /* Read the next line from the file */
+
+ if (!fgets(buffer, CONFIG_FTP_MAXPATH, instream))
+ {
+ break;
+ }
+
+ /* Remove any trailing CR-LF from the line */
+
+ ftpc_stripcrlf(buffer);
+
+ /* Check for empty file names */
+
+ if (buffer[0] == '\0')
+ {
+ break;
+ }
+ nvdbg("File: %s\n", buffer);
+
+ /* Perform the callback operation */
+
+ callback(buffer, arg);
+ }
+}
+
+/****************************************************************************
+ * Name: ftpc_recvdir
+ *
+ * Description:
+ * Get the directory listing.
+ *
+ ****************************************************************************/
+
+static int ftpc_recvdir(FAR struct ftpc_session_s *session,
+ FAR FILE *outstream)
+{
+ int ret;
+
+ /* Verify that we are still connected to the server */
+
+ if (!ftpc_connected(session))
+ {
+ ndbg("Not connected to server\n");
+ return ERROR;
+ }
+
+ /* Setup for the transfer */
+
+ ftpc_xfrreset(session);
+ ret = ftpc_xfrinit(session);
+ if (ret != OK)
+ {
+ return ERROR;
+ }
+
+ /* Send the "NLST" command */
+
+ ret = ftpc_cmd(session, "NLST");
+ if (ret != OK)
+ {
+ return ERROR;
+ }
+
+ /* Accept the connection from the server */
+
+ ret = ftpc_sockaccept(&session->data, "r", FTPC_IS_PASSIVE(session));
+ if (ret != OK)
+ {
+ ndbg("ftpc_sockaccept() failed: %d\n", errno);
+ return ERROR;
+ }
+
+ /* Receive the NLST response */
+
+ ret = ftpc_recvtext(session, session->data.instream, outstream);
+ ftpc_sockclose(&session->data);
+ if (ret != OK)
+ {
+ return ERROR;
+ }
+
+ /* Get the server reply */
+
+ fptc_getreply(session);
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_listdir
+ *
+ * Description:
+ * Get a simple directory listing using NLST:
+ *
+ * NLST [<SP> <pathname>] <CRLF>
+ *
+ * We could do much, much more here using the LIST or MLST/MLSD commands,
+ * but the parsing is a bitch. See http://cr.yp.to/ftpparse.html
+ *
+ * NOTE: We expect to receive only well structured directory paths. Tilde
+ * expansion "~/xyz" and relative pathes (abc/def) because we do have
+ * special knowledge about the home and current directories. But otherwise
+ * the pathes are expected to be pre-sanitized: No . or .. in paths,
+ * no '//' in paths, etc.
+ *
+ ****************************************************************************/
+
+FAR struct ftpc_dirlist_s *ftpc_listdir(SESSION handle,
+ FAR const char *dirpath)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ struct ftpc_dirlist_s *dirlist;
+ FILE *filestream;
+ FAR char *abspath;
+ FAR char *tmpfname;
+ bool iscurdir;
+ unsigned int nnames;
+ int allocsize;
+ int ret;
+
+ /* Get the absolute path to the directory */
+
+ abspath = ftpc_abspath(session, dirpath);
+ ftpc_stripslash(abspath);
+
+ /* Is the directory also the remote current working directory? */
+
+ iscurdir = (strcmp(abspath, session->curdir) == 0);
+
+ /* Create a temporary file to hold the directory listing */
+
+ asprintf(&tmpfname, "%s/TMP%s.dat", CONFIG_FTP_TMPDIR, getpid());
+ filestream = fopen(tmpfname, "w+");
+ if (!filestream)
+ {
+ ndbg("Failed to create %s: %d\n", tmpfname, errno);
+ free(abspath);
+ free(tmpfname);
+ return NULL;
+ }
+
+ /* "CWD" first so that we get the directory contents, not the
+ * directory itself.
+ */
+
+ if (!iscurdir)
+ {
+ ret = ftpc_cmd(session, "CWD %s", abspath);
+ if (ret != OK)
+ {
+ ndbg("CWD to %s failed\n", abspath);
+ }
+ }
+
+ /* Send the NLST command with no arguments to get the entire contents of
+ * the directory.
+ */
+
+ ret = ftpc_recvdir(session, filestream);
+
+ /* Go back to the correct current working directory */
+
+ if (!iscurdir)
+ {
+ int tmpret = ftpc_cmd(session, "CWD %s", session->curdir);
+ if (tmpret != OK)
+ {
+ ndbg("CWD back to to %s failed\n", session->curdir);
+ }
+ }
+
+ /* Did we successfully receive the directory listing? */
+
+ dirlist = NULL;
+ if (ret == OK)
+ {
+ /* Count the number of names in the temporary file */
+
+ rewind(filestream);
+ ftpc_nlstparse(filestream, ftpc_dircount, &nnames);
+ if (!nnames)
+ {
+ ndbg("Nothing found in directory\n");
+ goto errout;
+ }
+
+ /* Allocate and initialize a directory container */
+
+ allocsize = SIZEOF_FTPC_DIRLIST(nnames);
+ dirlist = (struct ftpc_dirlist_s *)malloc(allocsize);
+ if (!dirlist)
+ {
+ ndbg("Failed to allocate dirlist\n");
+ goto errout;
+ }
+ dirlist->nnames = 0;
+
+ /* Then copy all of the directory strings into the container */
+
+ rewind(filestream);
+ ftpc_nlstparse(filestream, ftpc_dircount, &nnames);
+ DEBUGASSERT(nnames == dirlist->nnames);
+ }
+
+errout:
+ fclose(filestream);
+ free(abspath);
+ unlink(tmpfname);
+ free(tmpfname);
+ return dirlist;
+}
+
+/****************************************************************************
+ * Name: ftpc_dirfree
+ *
+ * Description:
+ * Release the allocated directory listing.
+ *
+ ****************************************************************************/
+
+void ftpc_dirfree(FAR struct ftpc_dirlist_s *dirlist)
+{
+ int i;
+
+ if (dirlist)
+ {
+ /* Free each directory name in the directory container */
+
+ for (i = 0; i < dirlist->nnames; i++)
+ {
+ /* NULL means that the caller stole the string */
+
+ if (dirlist->name[i])
+ {
+ free(dirlist->name[i]);
+ }
+ }
+
+ /* Then free the container itself */
+
+ free(dirlist);
+ }
+}
+
diff --git a/apps/netutils/ftpc/ftpc_login.c b/apps/netutils/ftpc/ftpc_login.c
new file mode 100644
index 000000000..f2697dde1
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_login.c
@@ -0,0 +1,177 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_login.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_login
+ *
+ * Description:
+ * Log into the server
+ *
+ ****************************************************************************/
+
+int ftpc_login(SESSION handle, FAR struct ftpc_login_s *login)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ int err;
+ int ret;
+
+ /* Verify that we are connected to a server */
+
+ if (!ftpc_connected(session))
+ {
+ ndbg("Not connected\n");
+ err = ENOTCONN;
+ goto errout_with_err;
+ }
+
+ /* Verify that we are not already logged in to the server */
+
+ if (ftpc_loggedin(session))
+ {
+ ndbg("Already logged in\n");
+ err = EINVAL;
+ goto errout_with_err;
+ }
+
+ /* Save the login parameter */
+
+ session->uname = decode_rfc1738(login->uname);
+ session->pwd = decode_rfc1738(login->pwd);
+ session->initdir = decode_rfc1738(login->rdir);
+
+ /* Is passive mode requested? */
+
+ FTPC_CLR_PASSIVE(session);
+ if (login->pasv)
+ {
+ FTPC_SET_PASSIVE(session);
+ }
+
+ /* The (Re-)login to the server */
+
+ ret = ftpc_relogin(session);
+ if (ret != OK)
+ {
+ ndbg("login failed: %d\n", errno);
+ goto errout;
+ }
+
+ return OK;
+
+errout_with_err:
+ set_errno(err);
+errout:
+ return ERROR;
+}
+
+/****************************************************************************
+ * Name: ftpc_relogin
+ *
+ * Description:
+ * Log in again after a loss of connection
+ *
+ ****************************************************************************/
+
+int ftpc_relogin(FAR struct ftpc_session_s *session)
+{
+ int err;
+ int ret;
+
+ /* Log into the server */
+
+ FTPC_CLR_LOGGEDIN(session);
+ ret = ftpc_cmd(session, "USER %s", session->uname);
+ if (ret != OK)
+ {
+ ndbg("USER %s cmd failed: %d\n", session->uname, errno);
+ return ERROR;
+ }
+
+ ret = ftpc_cmd(session, "PASS %s", session->pwd);
+ if (ret != OK)
+ {
+ ndbg("PASS %s cmd failed: %d\n", session->pwd, errno);
+ return ret;
+ }
+
+ FTPC_SET_LOGGEDIN(session);
+ session->homedir = ftpc_pwd((SESSION)session);
+ session->curdir = strdup(session->homedir);
+ session->prevdir = strdup(session->homedir);
+ if (session->initdir)
+ {
+ ftpc_chdir((SESSION)session, session->initdir);
+ }
+
+ return OK;
+}
diff --git a/apps/netutils/ftpc/ftpc_mkdir.c b/apps/netutils/ftpc/ftpc_mkdir.c
new file mode 100644
index 000000000..d11466112
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_mkdir.c
@@ -0,0 +1,93 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_mkdir.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_mkdir
+ *
+ * Description:
+ * Creates the named directory on the remote server.
+ *
+ ****************************************************************************/
+
+int ftpc_mkdir(SESSION handle, FAR const char *path)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ char *ptr;
+ int ret;
+
+ ptr = strdup(path);
+ ftpc_stripslash(ptr);
+
+ ret = ftpc_cmd(session, "MKD %s", ptr);
+ free(ptr);
+ return ret;
+}
diff --git a/apps/netutils/ftpc/ftpc_noop.c b/apps/netutils/ftpc/ftpc_noop.c
new file mode 100644
index 000000000..5e6874f02
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_noop.c
@@ -0,0 +1,85 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_noop.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_noop
+ *
+ * Description:
+ * No operation command. Using NOOP allows us to make sure that commands
+ * are passed over the control connection without changing the status of
+ * any data transaction or server status. This is useful for (1)
+ * maintaining connections during long IDLE times and (2) It can also be
+ * used as a harmless way of detecting timeouts.
+ *
+ ****************************************************************************/
+
+int ftpc_noop(SESSION handle)
+{
+ return ftpc_cmd((FAR struct ftpc_session_s *)handle, "NOOP");
+}
diff --git a/apps/netutils/ftpc/ftpc_putfile.c b/apps/netutils/ftpc/ftpc_putfile.c
new file mode 100644
index 000000000..c05112402
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_putfile.c
@@ -0,0 +1,406 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_putfile.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <libgen.h>
+#include <debug.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_waitoutput
+ *
+ * Description:
+ * Wait to send data.
+ *
+ ****************************************************************************/
+
+static int ftpc_waitoutput(FAR struct ftpc_session_s *session)
+{
+ int ret;
+
+ do
+ {
+ ret = ftpc_waitdata(session, session->data.outstream, false);
+ if (ret < 0)
+ {
+ return ERROR;
+ }
+ }
+ while(ret == 0);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ftpc_sendbinary
+ *
+ * Description:
+ * Send a binary file to the remote host.
+ *
+ ****************************************************************************/
+
+static int ftpc_sendbinary(FAR struct ftpc_session_s *session,
+ FAR FILE *linstream, FILE *routstream)
+{
+ FAR char *buf;
+ ssize_t nread;
+ ssize_t nwritten;
+ int ret = OK;
+
+ buf = (char *)malloc(CONFIG_FTP_BUFSIZE);
+ while (!feof(linstream))
+ {
+ nread = fread(buf, sizeof(char), CONFIG_FTP_BUFSIZE, linstream);
+ if (nread <= 0)
+ {
+ (void)ftpc_xfrabort(session, linstream);
+ ret = ERROR;
+ break;
+ }
+
+ if (ftpc_waitoutput(session) != 0)
+ {
+ ret = ERROR;
+ break;
+ }
+
+ nwritten = fwrite(buf, sizeof(char), nread, routstream);
+ if (nwritten != nread)
+ {
+ (void)ftpc_xfrabort(session, routstream);
+ ret = ERROR;
+ break;
+ }
+
+ session->size += nread;
+ }
+
+ free(buf);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpc_sendtext
+ *
+ * Description:
+ * Send a text file to the remote host.
+ *
+ ****************************************************************************/
+
+static int ftpc_sendtext(FAR struct ftpc_session_s *session,
+ FAR FILE *linstream, FAR FILE *routstream)
+{
+ char *buf = (char *)malloc(CONFIG_FTP_BUFSIZE);
+ int c;
+ int ret = OK;
+
+ while((c = fgetc(linstream)) != EOF)
+ {
+ if (ftpc_waitoutput(session) != 0)
+ {
+ break;
+ }
+
+ if (c == '\n')
+ {
+ if (fputc('\r', routstream) == EOF)
+ {
+ (void)ftpc_xfrabort(session, routstream);
+ ret = ERROR;
+ break;
+ }
+
+ session->size++;
+ }
+
+ if (fputc(c, routstream) == EOF)
+ {
+ (void)ftpc_xfrabort(session, routstream);
+ ret = ERROR;
+ break;
+ }
+
+ session->size++;
+ }
+
+ free(buf);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpc_sendfile
+ *
+ * Description:
+ * Send the file to the remote host.
+ *
+ ****************************************************************************/
+
+static int ftpc_sendfile(struct ftpc_session_s *session, const char *path,
+ FILE *stream, uint8_t how, uint8_t xfrmode)
+{
+ long offset = session->offset;
+ int ret;
+
+ session->offset = 0;
+
+ /* Were we asked to store a file uniquely? Does the host support the STOU
+ * command?
+ */
+
+ if (how == FTPC_PUT_UNIQUE && !FTPC_HAS_STOU(session))
+ {
+ /* We cannot store a file uniquely */
+
+ return ERROR;
+ }
+
+ ftpc_xfrreset(session);
+ FTPC_SET_PUT(session);
+
+ /* Initialize for the transfer */
+
+ ret = ftpc_xfrinit(session);
+ if (ret != OK)
+ {
+ return ERROR;
+ }
+
+ ftpc_xfrmode(session, xfrmode);
+
+ if (offset > 0)
+ {
+ ret = ftpc_cmd(session, "REST %ld", offset);
+ session->size = offset;
+ session->rstrsize = offset;
+ }
+
+ switch(how)
+ {
+ case FTPC_PUT_UNIQUE:
+ ret = ftpc_cmd(session, "STOU %s", path);
+
+ /* Check for "502 Command not implemented" */
+
+ if (session->code == 502)
+ {
+ /* The host does not support the STOU command */
+
+ FTPC_CLR_STOU(session);
+ }
+ break;
+
+ case FTPC_PUT_APPEND:
+ ret = ftpc_cmd(session, "APPE %s", path);
+ break;
+
+ case FTPC_PUT_NORMAL:
+ default:
+ ret = ftpc_cmd(session, "STOR %s", path);
+ break;
+ }
+
+ if (how == FTPC_PUT_UNIQUE)
+ {
+ /* Determine the remote filename */
+
+ char *str = strstr(session->reply, " for ");
+ if (str)
+ {
+ int len;
+
+ str += 5;
+ len = strlen(str);
+ if (len)
+ {
+ free(session->lname);
+ if (*str == '\'')
+ {
+ session->lname = strndup(str+1, len-3);
+ }
+ else
+ {
+ session->lname = strndup(str, len-1);
+ nvdbg("parsed unique filename as '%s'\n", session->lname);
+ }
+ }
+ }
+ }
+
+ ret = ftpc_sockaccept(&session->data, "w", FTPC_IS_PASSIVE(session));
+ if (ret != OK)
+ {
+ ndbg("Data connection not accepted\n");
+ return ERROR;
+ }
+
+ if (xfrmode == FTPC_XFRMODE_ASCII)
+ {
+ ret = ftpc_sendbinary(session, stream, session->data.instream);
+ }
+ else
+ {
+ ret = ftpc_sendtext(session, stream, session->data.instream);
+ }
+
+ ftpc_sockflush(&session->data);
+ ftpc_sockclose(&session->data);
+
+ if (ret == 0)
+ {
+ fptc_getreply(session);
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_putfile
+ *
+ * Description:
+ * Put a file on the remote host.
+ *
+ ****************************************************************************/
+
+int ftp_putfile(SESSION handle, const char *lname, const char *rname,
+ uint8_t how, uint8_t xfrmode)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ struct stat statbuf;
+ FILE *finstream;
+ int ret;
+
+ /* Make sure that the local file exists */
+
+ ret = stat(lname, &statbuf);
+ if (ret != OK)
+ {
+ ndbg("stat() failed: %d\n", errno);
+ return ERROR;
+ }
+
+ /* Make sure that the local name does not refer to a directory */
+
+ if (S_ISDIR(statbuf.st_mode))
+ {
+ ndbg("%s is a directory\n", lname);
+ return ERROR;
+ }
+
+ /* Open the local file for reading */
+
+ finstream = fopen(lname, "r");
+ if (!finstream == 0)
+ {
+ ndbg("fopen() failed: %d\n", errno);
+ return ERROR;
+ }
+
+ /* Configure for the transfer */
+
+ session->filesize = statbuf.st_size;
+ free(session->rname);
+ free(session->lname);
+ session->rname = strdup(lname);
+ session->lname = strdup(rname);
+
+ /* Are we resuming a transfer? */
+
+ session->offset = 0;
+ if (how == FTPC_PUT_RESUME)
+ {
+ /* Yes... Get the size of the file. This will only work if the
+ * server supports the SIZE command.
+ */
+
+ session->offset = ftpc_filesize(session, rname);
+ if (session->offset == (off_t)ERROR)
+ {
+ ndbg("Failed to get size of remote file: %s\n", rname);
+ }
+ else
+ {
+ /* Seek to the offset in the file corresponding to the size
+ * that we have already sent.
+ */
+
+ ret = fseek(finstream, session->offset, SEEK_SET);
+ if (ret != OK)
+ {
+ ndbg("fseek failed: %d\n", errnoo);
+ fclose(finstream);
+ return ERROR;
+ }
+ }
+ }
+
+ ret = ftpc_sendfile(session, rname, finstream, how, xfrmode);
+ fclose(finstream);
+ return ret;
+}
diff --git a/apps/netutils/ftpc/ftpc_pwd.c b/apps/netutils/ftpc/ftpc_pwd.c
new file mode 100644
index 000000000..f6bde0e13
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_pwd.c
@@ -0,0 +1,121 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_pwd.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <debug.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_pwd
+ *
+ * Descripton:
+ * Returns the current working directory on the remote server.
+ *
+ ****************************************************************************/
+
+FAR char *ftpc_pwd(SESSION handle)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ FAR char *start;
+ FAR char *end;
+ FAR char *pwd;
+ FAR char *ptr;
+ int ret;
+
+ ret = ftpc_cmd(session, "PWD");
+ start = strchr(session->reply, '\"');
+ if (!start)
+ {
+ ndbg("Opening quote not found\n");
+ return NULL;
+ }
+
+ start++;
+ end = strchr(start, '\"');
+ if (!end)
+ {
+ ndbg("Clsoing quote not found\n");
+ return NULL;
+ }
+
+ pwd = (char *)malloc(end-start+1);
+ strncpy(pwd, start, end-start);
+ ftpc_stripslash(pwd);
+
+ /* Change DOS style directory separator ('\') to UNIX style ('/') */
+
+ for (ptr = pwd; *ptr; ptr++)
+ {
+ if (*ptr == '\\')
+ {
+ *ptr = '/';
+ }
+ }
+ return pwd;
+}
diff --git a/apps/netutils/ftpc/ftpc_quit.c b/apps/netutils/ftpc/ftpc_quit.c
new file mode 100644
index 000000000..daae04e88
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_quit.c
@@ -0,0 +1,92 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_quit.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <time.h>
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_quit
+ *
+ * Description:
+ * Ends the FTP session with the remote computer and exits ftp
+ *
+ ****************************************************************************/
+
+int ftpc_quit(SESSION handle)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ int ret = OK;
+
+ if (ftpc_connected(session))
+ {
+ session->replytimeo = 10 * CLOCKS_PER_SEC;
+ ret = ftpc_cmd(session, "QUIT");
+ }
+
+ ftpc_disconnect(handle);
+ return ret;
+}
diff --git a/apps/netutils/ftpc/ftpc_rename.c b/apps/netutils/ftpc/ftpc_rename.c
new file mode 100644
index 000000000..c1a80c289
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_rename.c
@@ -0,0 +1,104 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_rename.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_rename
+ *
+ * Description:
+ * Rename a file on the remote server.
+ *
+ ****************************************************************************/
+
+int ftpc_rename(SESSION handle, FAR const char *oldname, FAR const char *newname)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ char *oldcopy;
+ char *newcopy;
+ int ret;
+
+ oldcopy = strdup(oldname);
+ ftpc_stripslash(oldcopy);
+ ret = ftpc_cmd(session, "RNFR %s", oldcopy);
+ if (ret != OK)
+ {
+ free(oldcopy);
+ return ERROR;
+ }
+
+ newcopy = strdup(newname);
+ ftpc_stripslash(newcopy);
+ ret = ftpc_cmd(session, "RNTO %s", newcopy);
+
+ free(oldcopy);
+ free(newcopy);
+ return ret;
+}
diff --git a/apps/netutils/ftpc/ftpc_response.c b/apps/netutils/ftpc/ftpc_response.c
new file mode 100644
index 000000000..3bf1ee54b
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_response.c
@@ -0,0 +1,84 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_response.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <string.h>
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_response
+ *
+ * Description:
+ * Return the response string from the last command. This is allocated
+ * memory that must be freed using free() when it is no longer needed.
+ *
+ ****************************************************************************/
+
+FAR char *ftpc_response(SESSION handle)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ return strndup(session->reply, CONFIG_FTP_MAXREPLY);
+}
diff --git a/apps/netutils/ftpc/ftpc_rmdir.c b/apps/netutils/ftpc/ftpc_rmdir.c
new file mode 100644
index 000000000..caa50392f
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_rmdir.c
@@ -0,0 +1,92 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_rmdir.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_rmdir
+ *
+ * Description:
+ * Deletes the named directory on the remote server.
+ *
+ ****************************************************************************/
+int ftpc_rmdir(SESSION handle, FAR const char *path)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ char *ptr;
+ int ret;
+
+ ptr = strdup(path);
+ ftpc_stripslash(ptr);
+
+ ret = ftpc_cmd(session, "RMD %s", ptr);
+ free(ptr);
+ return ret;
+}
+
diff --git a/apps/netutils/ftpc/ftpc_socket.c b/apps/netutils/ftpc/ftpc_socket.c
new file mode 100644
index 000000000..500f20995
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_socket.c
@@ -0,0 +1,390 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_socket.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <sys/socket.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <debug.h>
+#include <errno.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_sockinit
+ *
+ * Description:
+ * Initialize a socket. Create the socket and "wrap" it as C standard
+ * incoming and outgoing streams.
+ *
+ ****************************************************************************/
+
+int ftpc_sockinit(FAR struct ftpc_socket_s *sock)
+{
+ int dupsd;
+
+ /* Initialize the socket structure */
+
+ memset(sock, 0, sizeof(struct ftpc_socket_s));
+ sock->raddr.sin_family = AF_INET;
+
+ /* Create a socket descriptor */
+
+ sock->sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sock->sd < 0)
+ {
+ ndbg("socket() failed: %d\n", errno);
+ goto errout;
+ }
+
+ /* 'dup' the socket descriptor to create an independent input stream */
+
+ dupsd = dup(sock->sd);
+ if (dupsd < 0)
+ {
+ ndbg("socket() failed: %d\n", errno);
+ goto errout_with_sd;
+ }
+
+ /* Call fdopen to "wrap" the input stream with C buffered I/O */
+
+ sock->instream = fdopen(dupsd, "r");
+ if (!sock->instream)
+ {
+ ndbg("fdopen() failed: %d\n", errno);
+ close(dupsd);
+ goto errout_with_sd;
+ }
+
+ /* 'dup' the socket descriptor to create an independent output stream */
+
+ dupsd = dup(sock->sd);
+ if (dupsd < 0)
+ {
+ ndbg("socket() failed: %d\n", errno);
+ goto errout_with_instream;
+ }
+
+ /* Call fdopen to "wrap" the output stream with C buffered I/O */
+
+ sock->outstream = fdopen(dupsd, "w");
+ if (!sock->outstream)
+ {
+ ndbg("fdopen() failed: %d\n", errno);
+ close(dupsd);
+ goto errout_with_instream;
+ }
+
+ return OK;
+
+errout_with_instream:
+ fclose(sock->instream);
+errout_with_sd:
+ close(sock->sd);
+errout:
+ return ERROR;
+}
+
+/****************************************************************************
+ * Name: ftpc_sockclose
+ *
+ * Description:
+ * Close a socket
+ *
+ ****************************************************************************/
+
+void ftpc_sockclose(struct ftpc_socket_s *sock)
+{
+ fclose(sock->instream);
+ fclose(sock->outstream);
+ close(sock->sd);
+ memset(sock, 0, sizeof(struct ftpc_socket_s));
+}
+
+/****************************************************************************
+ * Name: ftpc_sockconnect
+ *
+ * Description:
+ * Connect the socket to the host
+ *
+ ****************************************************************************/
+
+int ftpc_sockconnect(struct ftpc_socket_s *sock, struct sockaddr_in *addr)
+{
+ int ret;
+
+ /* Connect to the socket */
+
+ ret = connect(sock->sd, (struct sockaddr *)addr, sizeof(struct sockaddr));
+ if (ret < 0)
+ {
+ ndbg("connect() failed: %d\n", errno);
+ close(sock->sd);
+ return ERROR;
+ }
+
+ /* Get the local address of the socket */
+
+ ret = ftpc_sockgetsockname(sock, &sock->laddr);
+ if (ret < 0)
+ {
+ ndbg("ftpc_sockgetsockname() failed: %d\n", errno);
+ close(sock->sd);
+ return ERROR;
+ }
+ sock->connected = true;
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ftpc_sockcopy
+ *
+ * Description:
+ * Copy the socket state from one location to another.
+ *
+ ****************************************************************************/
+
+void ftpc_sockcopy(FAR struct ftpc_socket_s *dest,
+ FAR const struct ftpc_socket_s *src)
+{
+ memcpy(&dest->raddr, &src->raddr, sizeof(struct sockaddr_in));
+ memcpy(&dest->laddr, &src->laddr, sizeof(struct sockaddr_in));
+ dest->connected = ftpc_sockconnected(src);
+}
+
+/****************************************************************************
+ * Name: ftpc_sockaccept
+ *
+ * Description:
+ * Accept a connection from the server.
+ *
+ ****************************************************************************/
+
+int ftpc_sockaccept(struct ftpc_socket_s *sock, const char *mode, bool passive)
+{
+ struct sockaddr addr;
+ socklen_t addrlen;
+ int dupsd;
+ int sd;
+
+ /* In active mode FTP the client connects from a random port (N>1023) to the
+ * FTP server's command port, port 21. Then, the client starts listening to
+ * port N+1 and sends the FTP command PORT N+1 to the FTP server. The server
+ * will then connect back to the client's specified data port from its local
+ * data port, which is port 20. In passive mode FTP the client initiates
+ * both connections to the server, solving the problem of firewalls filtering
+ * the incoming data port connection to the client from the server. When
+ * opening an FTP connection, the client opens two random ports locally
+ * (N>1023 and N+1). The first port contacts the server on port 21, but
+ * instead of then issuing a PORT command and allowing the server to connect
+ * back to its data port, the client will issue the PASV command. The result
+ * of this is that the server then opens a random unprivileged port (P >
+ * 1023) and sends the PORT P command back to the client. The client then
+ * initiates the connection from port N+1 to port P on the server to transfer
+ * data.
+ */
+
+ if (!passive)
+ {
+ addrlen = sizeof(addr);
+ sd = accept(sock->sd, &addr, &addrlen);
+ close(sock->sd);
+ if (sd == -1)
+ {
+ ndbg("accept() failed: %d\n", errno);
+ sock->sd = -1;
+ return ERROR;
+ }
+
+ sock->sd = sd;
+ memcpy(&sock->laddr, &addr, sizeof(sock->laddr));
+ }
+
+ /* Create in/out C buffer I/O streams on the cmd channel */
+
+ fclose(sock->instream);
+ fclose(sock->outstream);
+
+ /* Dup the socket descriptor and create the incoming stream */
+
+ dupsd = dup(sock->sd);
+ if (dupsd < 0)
+ {
+ ndbg("dup() failed: %d\n", errno);
+ goto errout_with_sd;
+ }
+
+ sock->instream = fdopen(dupsd, mode);
+ if (!sock->instream)
+ {
+ ndbg("fdopen() failed: %d\n", errno);
+ close(dupsd);
+ goto errout_with_sd;
+ }
+
+ /* Dup the socket descriptor and create the outgoing stream */
+
+ dupsd = dup(sock->sd);
+ if (dupsd < 0)
+ {
+ ndbg("dup() failed: %d\n", errno);
+ goto errout_with_instream;
+ }
+
+ sock->outstream = fdopen(dupsd, mode);
+ if (!sock->outstream)
+ {
+ ndbg("fdopen() failed: %d\n", errno);
+ close(dupsd);
+ goto errout_with_instream;
+ }
+
+ return OK;
+
+errout_with_instream:
+ fclose(sock->instream);
+errout_with_sd:
+ close(sock->sd);
+ sock->sd = -1;
+ return ERROR;
+}
+
+/****************************************************************************
+ * Name: ftpc_socklisten
+ *
+ * Description:
+ * Bind the socket to local address and wait for connection from the server.
+ *
+ ****************************************************************************/
+
+int ftpc_socklisten(struct ftpc_socket_s *sock)
+{
+ unsigned int addrlen = sizeof(sock->laddr);
+ int ret;
+
+ /* Bind the local socket to the local address */
+
+ sock->laddr.sin_port = 0;
+ ret = bind(sock->sd, (struct sockaddr *)&sock->laddr, addrlen);
+ if (ret < 0)
+ {
+ ndbg("bind() failed: %d\n", errno);
+ return ERROR;
+ }
+
+ /* Wait for the connection to the server */
+
+ if (listen(sock->sd, 1) == -1)
+ {
+ return ERROR;
+ }
+
+ /* Then get the local address selected by NuttX */
+
+ ret = ftpc_sockgetsockname(sock, &sock->laddr);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpc_sockprintf
+ *
+ * Description:
+ * printf to a socket stream
+ *
+ ****************************************************************************/
+
+int ftpc_sockprintf(struct ftpc_socket_s *sock, const char *str, ...)
+{
+ va_list ap;
+ int r;
+
+ va_start(ap, str);
+ r = vfprintf(sock->outstream, str, ap);
+ va_end(ap);
+ return r;
+}
+
+/****************************************************************************
+ * Name: ftpc_sockgetsockname
+ *
+ * Description:
+ * Get the address of the local socket
+ *
+ ****************************************************************************/
+
+int ftpc_sockgetsockname(FAR struct ftpc_socket_s *sock,
+ FAR struct sockaddr_in *addr)
+{
+ unsigned int len = sizeof(struct sockaddr_in);
+ int ret;
+
+ ret = getsockname(sock->sd, (struct sockaddr *)addr, &len);
+ if (ret < 0)
+ {
+ ndbg("getsockname failed: %d\n", errno);
+ return ERROR;
+ }
+ return OK;
+}
diff --git a/apps/netutils/ftpc/ftpc_transfer.c b/apps/netutils/ftpc/ftpc_transfer.c
new file mode 100644
index 000000000..bce30e302
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_transfer.c
@@ -0,0 +1,400 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_transfer.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <poll.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+#include <debug.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftp_pasvmode
+ *
+ * Description:
+ * Enter passive mode.
+ *
+ * In active mode FTP the client connects from a random port (N>1023) to the
+ * FTP server's command port, port 21. Then, the client starts listening to
+ * port N+1 and sends the FTP command PORT N+1 to the FTP server. The server
+ * will then connect back to the client's specified data port from its local
+ * data port, which is port 20. In passive mode FTP the client initiates
+ * both connections to the server, solving the problem of firewalls filtering
+ * the incoming data port connection to the client from the server. When
+ * opening an FTP connection, the client opens two random ports locally
+ * (N>1023 and N+1). The first port contacts the server on port 21, but
+ * instead of then issuing a PORT command and allowing the server to connect
+ * back to its data port, the client will issue the PASV command. The result
+ * of this is that the server then opens a random unprivileged port (P >
+ * 1023) and sends the PORT P command back to the client. The client then
+ * initiates the connection from port N+1 to port P on the server to transfer
+ * data.
+ *
+ ****************************************************************************/
+
+static int ftp_pasvmode(struct ftpc_session_s *session,
+ uint8_t addrport[6])
+{
+ int tmpap[6];
+ char *ptr;
+ int nscan;
+ int ret;
+ int i;
+
+ /* Does this host support the PASV command */
+
+ if (!FTPC_HAS_PASV(session))
+ {
+ ndbg("Host doesn't support passive mode\n");
+ return ERROR;
+ }
+
+ /* Request passive mode */
+
+ ret = ftpc_cmd(session, "PASV");
+ if (ret < 0 || !ftpc_connected(session))
+ {
+ return ERROR;
+ }
+
+ /* Skip over any leading stuff before address begins */
+
+ ptr = session->reply + 4;
+ while (!isdigit((int)*ptr))
+ {
+ ptr++;
+ }
+
+ /* The response is then 6 integer values: four representing the
+ * IP address and two representing the port number.
+ */
+
+ nscan = sscanf(ptr, "%d,%d,%d,%d,%d,%d",
+ &tmpap[0], &tmpap[1], &tmpap[2],
+ &tmpap[3], &tmpap[4], &tmpap[5]);
+ if (nscan != 6)
+ {
+ ndbg("Error parsing PASV reply: '%s'\n", session->reply);
+ return ERROR;
+ }
+
+ /* Then copy the sscanf'ed values as bytes */
+
+
+ for (i = 0; i < 6; i++)
+ {
+ addrport[i] = (uint8_t)(tmpap[i] & 0xff);
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_xfrinit
+ *
+ * Description:
+ * Perform common transfer setup logic.
+ *
+ ****************************************************************************/
+
+int ftpc_xfrinit(FAR struct ftpc_session_s *session)
+{
+ struct sockaddr_in addr;
+ uint8_t addrport[6];
+ uint8_t *paddr;
+ uint8_t *pport;
+ int ret;
+
+ /* We must be connected to initiate a transfer */
+
+ if (!ftpc_connected(session))
+ {
+ goto errout;
+ }
+
+ /* Initialize the data channel */
+
+ ret = ftpc_sockinit(&session->data);
+ if (ret != OK)
+ {
+ ndbg("ftpc_sockinit() failed: %d\n", errno);
+ goto errout;
+ }
+
+ /* Duplicate the address and connection information of the command channel */
+
+ ftpc_sockcopy(&session->data, &session->cmd);
+
+ /* Should we enter passive mode? */
+
+ if (FTPC_IS_PASSIVE(session))
+ {
+ /* Yes.. going passive. */
+
+ ret = ftp_pasvmode(session, addrport);
+ if (ret != OK)
+ {
+ goto errout_with_data;
+ }
+ }
+
+ /* Configure the data socket */
+
+ ftpc_sockgetsockname(&session->cmd, &addr);
+ memcpy(&addr.sin_addr, addrport, (size_t)4);
+ memcpy(&addr.sin_port, addrport+4, (size_t)2);
+
+ /* Connect the data socket */
+
+ ret = ftpc_sockconnect(&session->data, &addr);
+ if (ret < 0)
+ {
+ ndbg("ftpc_sockconnect() failed: %d\n", errno);
+ goto errout_with_data;
+ }
+ else
+ {
+ /* Wait for the connection to be established */
+
+ ftpc_socklisten(&session->data);
+
+ /* Then send our local data channel address to the server */
+
+ paddr = (uint8_t *)&session->data.laddr.sin_addr;
+ pport = (uint8_t *)&session->data.laddr.sin_port;
+
+ ret = ftpc_cmd(session, "PORT %d,%d,%d,%d,%d,%d",
+ paddr[0], paddr[1], paddr[2],
+ paddr[3], pport[0], pport[1]);
+ if (ret < 0)
+ {
+ ndbg("ftpc_cmd() failed: %d\n", errno);
+ goto errout_with_data;
+ }
+ }
+ return OK;
+
+ errout_with_data:
+ ftpc_sockclose(&session->data);
+ errout:
+ return ERROR;
+}
+
+/****************************************************************************
+ * Name: ftpc_xfrreset
+ *
+ * Description:
+ * Reset transfer variables
+ *
+ ****************************************************************************/
+
+void ftpc_xfrreset(struct ftpc_session_s *session)
+{
+ session->size = 0;
+ session->flags &= ~FTPC_XFER_FLAGS;
+ session->rstrsize = 0;
+}
+
+/****************************************************************************
+ * Name: ftpc_xfrmode
+ *
+ * Description:
+ * Select ASCII or Binary transfer mode
+ *
+ ****************************************************************************/
+
+int ftpc_xfrmode(struct ftpc_session_s *session, uint8_t xfrmode)
+{
+ int ret;
+
+ DEBUGASSERT(xfrmode != FTPC_XFRMODE_UNKNOWN);
+ if (session->xfrmode != xfrmode)
+ {
+ ret = ftpc_cmd(session, "TYPE %c", xfrmode == FTPC_XFRMODE_ASCII ? 'A' : 'I');
+ session->xfrmode = xfrmode;
+ }
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ftpc_xfrabort
+ *
+ * Description:
+ * Abort a transfer in progress
+ *
+ ****************************************************************************/
+
+int ftpc_xfrabort(FAR struct ftpc_session_s *session, FAR FILE *stream)
+{
+ char buffer[CONFIG_FTP_BUFSIZE];
+ FAR struct pollfd fds;
+ int ret;
+
+ /* Make sure that we are still connected */
+
+ if (!ftpc_connected(session))
+ {
+ return ERROR;
+ }
+
+ /* Check if there is data waiting to be read from the cmd channel */
+
+ fds.fd = session->cmd.sd;
+ fds.events = POLLIN;
+ ret = poll(&fds, 1, 0);
+ if (ret > 0)
+ {
+ /* Read data from command channel */
+
+ nvdbg("Flush cmd channel data\n");
+ while (stream && fread(buffer, 1, CONFIG_FTP_BUFSIZE, stream) > 0);
+ return OK;
+ }
+
+ FTPC_SET_INTERRUPT(session);
+
+ /* Send the Telnet interrupt sequence to abort the transfer:
+ * <IAC IP><IAC DM>ABORT<CR><LF>
+ */
+
+ ndbg("Telnet ABORt sequence\n");
+ ftpc_sockprintf(&session->cmd, "%c%c", TELNET_IAC, TELNET_IP); /* Interrupt process */
+ ftpc_sockprintf(&session->cmd, "%c%c", TELNET_IAC, TELNET_DM); /* Telnet synch signal */
+ ftpc_sockprintf(&session->cmd, "ABOR\r\n"); /* Abort */
+ ftpc_sockflush(&session->cmd);
+
+ /* Read remaining bytes from connection */
+
+ while (stream && fread(buffer, 1, CONFIG_FTP_BUFSIZE, stream) > 0);
+ while(stream && fread(buffer, 1, CONFIG_FTP_BUFSIZE, stream) > 0)
+
+ /* Get the ABORt reply */
+
+ fptc_getreply(session);
+
+ /* Expected replys are: "226 Closing data connection" or
+ * "426 Connection closed; transfer aborted"
+ */
+
+ if (session->code != 226 && session->code != 426)
+ {
+ nvdbg("Expected 226 or 426 reply\n");
+ }
+ else
+ {
+ /* Get the next reply */
+
+ fptc_getreply(session);
+
+ /* Expected replys are: or "225 Data connection open; no transfer in progress"
+ * "226 Closing data connection"
+ */
+
+ if (session->code != 226 && session->code != 225)
+ {
+ nvdbg("Expected 225 or 226 reply\n");
+ }
+ }
+
+ return ERROR;
+}
+
+/****************************************************************************
+ * Name: ftpc_waitdata
+ *
+ * Description:
+ * Wait for dta to be available on the provided stream.
+ *
+ ****************************************************************************/
+
+int ftpc_waitdata(FAR struct ftpc_session_s *session, FAR FILE *stream, bool rdwait)
+{
+ FAR struct pollfd fds;
+ int ret;
+
+ /* Check the stream to see if it has input OR is ready for output */
+
+ fds.fd = fileno(stream);
+ fds.events = rdwait ? POLLIN : POLLOUT;
+ ret = poll(&fds, 1, 10*1000);
+ if (ret < 0)
+ {
+ if (errno == EINTR)
+ {
+ return OK;
+ }
+ return ERROR;
+ }
+
+ return ret;
+}
+
+
+
diff --git a/apps/netutils/ftpc/ftpc_unlink.c b/apps/netutils/ftpc/ftpc_unlink.c
new file mode 100644
index 000000000..3a49374de
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_unlink.c
@@ -0,0 +1,85 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_unlink.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <apps/ftpc.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_unlink
+ *
+ * Descripton:
+ * Delete the given file from the remote server.
+ *
+ ****************************************************************************/
+
+int ftpc_unlink(SESSION handle, FAR const char *path)
+{
+ FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
+ int ret;
+
+ ret = ftpc_cmd(session, "DELE %s", path);
+ return ret;
+}
diff --git a/apps/netutils/ftpc/ftpc_utils.c b/apps/netutils/ftpc/ftpc_utils.c
new file mode 100644
index 000000000..46944e4b2
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_utils.c
@@ -0,0 +1,251 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_utils.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdlib.h>
+
+#include "ftpc_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_nibble
+ *
+ * Description:
+ * Convert a ASCII hex 'digit' to binary
+ *
+ ****************************************************************************/
+
+int ftpc_nibble(char ch)
+{
+ if (ch >= '0' && ch <= '9')
+ {
+ return (unsigned int)ch - '0';
+ }
+ else if (ch >= 'A' && ch <= 'F')
+ {
+ return (unsigned int)ch - 'A' + 10;
+ }
+ else if (ch >= 'a' && ch <= 'f')
+ {
+ return (unsigned int)ch - 'a' + 10;
+ }
+ return ERROR;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpc_reset
+ *
+ * Description:
+ * Reset the FTP session.
+ *
+ ****************************************************************************/
+
+void ftpc_reset(struct ftpc_session_s *session)
+{
+ ftpc_sockclose(&session->data);
+ ftpc_sockclose(&session->cmd);
+ free(session->uname);
+ session->uname = NULL;
+ free(session->pwd);
+ session->pwd = NULL;
+ free(session->initdir);
+ session->initdir = NULL;
+ session->flags = FTPC_FLAGS_INIT;
+ session->xfrmode = FTPC_XFRMODE_UNKNOWN;
+ session->code = 0;
+ session->replytimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC;
+ session->conntimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC;
+}
+
+/****************************************************************************
+ * Name: ftpc_curdir
+ *
+ * Description:
+ * Update the current working directory
+ *
+ ****************************************************************************/
+
+void ftpc_curdir(struct ftpc_session_s *session)
+{
+ free(session->prevdir);
+ session->prevdir = session->curdir;
+ session->curdir = ftpc_pwd((SESSION)session);
+}
+
+/****************************************************************************
+ * Name: ftpc_stripcrlf
+ *
+ * Description:
+ * Strip any trailing carriage returns or line feeds from a string.
+ *
+ ****************************************************************************/
+
+void ftpc_stripcrlf(FAR char *str)
+{
+ FAR char *ptr;
+ int len;
+
+ if (str)
+ {
+ len = strlen(str);
+ if (len > 0)
+ {
+ ptr = str + len - 1;
+ while (*ptr == '\r' || *ptr == '\n')
+ {
+ *ptr = '\0';
+ ptr--;
+ }
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: ftpc_stripslash
+ *
+ * Description:
+ * Strip any trailing slashes from a string.
+ *
+ ****************************************************************************/
+
+FAR char *ftpc_stripslash(FAR char *str)
+{
+ FAR char *ptr;
+
+ if (!str || !*str)
+ return str;
+
+ ptr = strchr(str, 0);
+ if(!ptr)
+ return str;
+ ptr--;
+ if(*ptr == '/') {
+ if(ptr != str) /* root directory */
+ *ptr = 0;
+ }
+ return str;
+}
+
+/****************************************************************************
+ * Name: ftpc_stripslash
+ *
+ * Description:
+ * Convert quoted hexadecimal constants to binary values.
+ *
+ ****************************************************************************/
+
+FAR char *ftpc_dequote(FAR const char *str)
+{
+ FAR char *allocstr = NULL;
+ FAR char *ptr;
+ int ms;
+ int ls;
+ int len;
+
+ if (str)
+ {
+ /* Allocate space for a modifiable copy of the string */
+
+ len = strlen(str);
+ allocstr = (FAR char*)malloc(len+1);
+ if (allocstr)
+ {
+ /* Search the string */
+
+ ptr = allocstr;
+ while (*str)
+ {
+ /* Check for a quoted hex value */
+
+ if (str[0] == '%')
+ {
+ /* Extract the hex value */
+
+ ms = ftpc_nibble(str[1]);
+ if (ms >= 0)
+ {
+ ls = ftpc_nibble(str[2]);
+ if (ls >= 0)
+ {
+ /* Save the binary value and skip ahead by 3 */
+
+ *ptr++ = (char)(ms << 8 | ls);
+ str += 3;
+ continue;
+ }
+ }
+ }
+
+ /* Just transfer the character */
+
+ *ptr++ = *str++;
+ }
+
+ /* NUL terminate */
+
+ *ptr = '\0';
+ }
+ }
+
+ return allocstr;
+}