+static int ftp_SendCommand( vlc_object_t *obj, access_sys_t *sys,
+ const char *fmt, ... )
+{
+ size_t fmtlen = strlen( fmt );
+ char fmtbuf[fmtlen + 3];
+
+ memcpy( fmtbuf, fmt, fmtlen );
+ memcpy( fmtbuf + fmtlen, "\r\n", 3 );
+
+ va_list args;
+ char *cmd;
+ int val;
+
+ va_start( args, fmt );
+ val = vasprintf( &cmd, fmtbuf, args );
+ va_end( args );
+ if( unlikely(val == -1) )
+ return -1;
+
+ msg_Dbg( obj, "sending request: \"%.*s\" (%d bytes)", val - 2, cmd, val );
+ if( net_Write( obj, sys->fd_cmd, NULL, cmd, val ) != val )
+ {
+ msg_Err( obj, "request failure" );
+ val = -1;
+ }
+ else
+ val = 0;
+ free( cmd );
+ return val;
+}
+
+/* TODO support this s**t :
+ RFC 959 allows the client to send certain TELNET strings at any moment,
+ even in the middle of a request:
+
+ * \377\377.
+ * \377\376x where x is one byte.
+ * \377\375x where x is one byte. The server is obliged to send \377\374x
+ * immediately after reading x.
+ * \377\374x where x is one byte.
+ * \377\373x where x is one byte. The server is obliged to send \377\376x
+ * immediately after reading x.
+ * \377x for any other byte x.
+
+ These strings are not part of the requests, except in the case \377\377,
+ where the request contains one \377. */
+static int ftp_RecvAnswer( vlc_object_t *obj, access_sys_t *sys,
+ int *restrict codep, char **restrict strp,
+ void (*cb)(void *, const char *), void *opaque )
+{
+ if( codep != NULL )
+ *codep = 500;
+ if( strp != NULL )
+ *strp = NULL;
+
+ char *resp = net_Gets( obj, sys->fd_cmd, NULL );
+ if( resp == NULL )
+ {
+ msg_Err( obj, "response failure" );
+ goto error;
+ }
+
+ char *end;
+ unsigned code = strtoul( resp, &end, 10 );
+ if( (end - resp) != 3 || (*end != '-' && *end != ' ') )
+ {
+ msg_Err( obj, "malformatted response" );
+ goto error;
+ }
+ msg_Dbg( obj, "received response: \"%s\"", resp );
+
+ if( *end == '-' ) /* Multi-line response */
+ {
+ bool done;
+
+ *end = ' ';
+ do
+ {
+ char *line = net_Gets( obj, sys->fd_cmd, NULL );
+ if( line == NULL )
+ {
+ msg_Err( obj, "response failure" );
+ goto error;
+ }
+
+ done = !strncmp( resp, line, 4 );
+ if( !done )
+ cb( opaque, line );
+ free( line );
+ }
+ while( !done );
+ }
+
+ if( codep != NULL )
+ *codep = code;
+ if( strp != NULL )
+ *strp = resp;
+ else
+ free( resp );
+ return code / 100;
+error:
+ free( resp );
+ return -1;
+}
+
+static void DummyLine( void *data, const char *str )
+{
+ (void) data; (void) str;
+}
+
+static int ftp_RecvCommand( vlc_object_t *obj, access_sys_t *sys,
+ int *restrict codep, char **restrict strp )
+{
+ return ftp_RecvAnswer( obj, sys, codep, strp, DummyLine, NULL );
+}
+