Commit affbecb0 authored by Mariusz Szczepańczyk's avatar Mariusz Szczepańczyk Committed by Michael Niedermayer

lavf/ftp: implement NLST method

Signed-off-by: 's avatarMichael Niedermayer <michael@niedermayer.cc>
parent 5fec7942
...@@ -38,6 +38,12 @@ typedef enum { ...@@ -38,6 +38,12 @@ typedef enum {
DISCONNECTED DISCONNECTED
} FTPState; } FTPState;
typedef enum {
UNKNOWN_METHOD,
NLST,
MLSD
} FTPListingMethod;
typedef struct { typedef struct {
const AVClass *class; const AVClass *class;
URLContext *conn_control; /**< Control connection */ URLContext *conn_control; /**< Control connection */
...@@ -56,6 +62,8 @@ typedef struct { ...@@ -56,6 +62,8 @@ typedef struct {
const char *anonymous_password; /**< Password to be used for anonymous user. An email should be used. */ const char *anonymous_password; /**< Password to be used for anonymous user. An email should be used. */
int write_seekable; /**< Control seekability, 0 = disable, 1 = enable. */ int write_seekable; /**< Control seekability, 0 = disable, 1 = enable. */
FTPState state; /**< State of data connection */ FTPState state; /**< State of data connection */
FTPListingMethod listing_method; /**< Called listing method */
char *features; /**< List of server's features represented as raw response */
char *dir_buffer; char *dir_buffer;
size_t dir_buffer_size; size_t dir_buffer_size;
size_t dir_buffer_offset; size_t dir_buffer_offset;
...@@ -192,6 +200,8 @@ static int ftp_send_command(FTPContext *s, const char *command, ...@@ -192,6 +200,8 @@ static int ftp_send_command(FTPContext *s, const char *command,
{ {
int err; int err;
av_dlog(s, "%s", command);
if (response) if (response)
*response = NULL; *response = NULL;
...@@ -449,32 +459,65 @@ static int ftp_set_dir(FTPContext *s) ...@@ -449,32 +459,65 @@ static int ftp_set_dir(FTPContext *s)
return 0; return 0;
} }
static int ftp_list(FTPContext *s) static int ftp_list_mlsd(FTPContext *s)
{ {
static const char *command = "MLSD\r\n"; static const char *command = "MLSD\r\n";
static const int mlsd_codes[] = {150, 500, 0}; /* 500 is incorrect code */ static const int mlsd_codes[] = {150, 500, 0}; /* 500 is incorrect code */
if (ftp_send_command(s, command, mlsd_codes, NULL) != 150) if (ftp_send_command(s, command, mlsd_codes, NULL) != 150)
return AVERROR(ENOSYS); return AVERROR(ENOSYS);
s->state = LISTING_DIR; s->listing_method = MLSD;
return 0;
}
static int ftp_list_nlst(FTPContext *s)
{
static const char *command = "NLST\r\n";
static const int nlst_codes[] = {226, 425, 426, 451, 450, 550, 0};
if (ftp_send_command(s, command, nlst_codes, NULL) != 226)
return AVERROR(ENOSYS);
s->listing_method = NLST;
return 0; return 0;
} }
static int ftp_has_feature(FTPContext *s, const char *feature_name);
static int ftp_list(FTPContext *s)
{
int ret;
s->state = LISTING_DIR;
if ((ret = ftp_list_mlsd(s)) < 0)
ret = ftp_list_nlst(s);
return ret;
}
static int ftp_has_feature(FTPContext *s, const char *feature_name)
{
if (!s->features)
return 0;
return av_stristr(s->features, feature_name) != NULL;
}
static int ftp_features(FTPContext *s) static int ftp_features(FTPContext *s)
{ {
static const char *feat_command = "FEAT\r\n"; static const char *feat_command = "FEAT\r\n";
static const char *enable_utf8_command = "OPTS UTF8 ON\r\n"; static const char *enable_utf8_command = "OPTS UTF8 ON\r\n";
static const int feat_codes[] = {211, 0}; static const int feat_codes[] = {211, 0};
static const int opts_codes[] = {200, 451, 0}; static const int opts_codes[] = {200, 451, 0};
char *feat = NULL;
if (ftp_send_command(s, feat_command, feat_codes, &feat) == 211) { av_freep(&s->features);
if (av_stristr(feat, "UTF8")) { if (ftp_send_command(s, feat_command, feat_codes, &s->features) != 211) {
if (ftp_send_command(s, enable_utf8_command, opts_codes, NULL) == 200) av_freep(&s->features);
s->utf8 = 1; }
}
if (ftp_has_feature(s, "UTF8")) {
if (ftp_send_command(s, enable_utf8_command, opts_codes, NULL) == 200)
s->utf8 = 1;
} }
av_freep(&feat);
return 0; return 0;
} }
...@@ -607,8 +650,10 @@ static int ftp_connect(URLContext *h, const char *url) ...@@ -607,8 +650,10 @@ static int ftp_connect(URLContext *h, const char *url)
FTPContext *s = h->priv_data; FTPContext *s = h->priv_data;
s->state = DISCONNECTED; s->state = DISCONNECTED;
s->listing_method = UNKNOWN;
s->filesize = -1; s->filesize = -1;
s->position = 0; s->position = 0;
s->features = NULL;
av_url_split(proto, sizeof(proto), av_url_split(proto, sizeof(proto),
credencials, sizeof(credencials), credencials, sizeof(credencials),
...@@ -815,6 +860,7 @@ static int ftp_close(URLContext *h) ...@@ -815,6 +860,7 @@ static int ftp_close(URLContext *h)
av_freep(&s->password); av_freep(&s->password);
av_freep(&s->hostname); av_freep(&s->hostname);
av_freep(&s->path); av_freep(&s->path);
av_freep(&s->features);
return 0; return 0;
} }
...@@ -878,10 +924,13 @@ static int64_t ftp_parse_date(const char *date) ...@@ -878,10 +924,13 @@ static int64_t ftp_parse_date(const char *date)
return INT64_C(1000000) * av_timegm(&tv); return INT64_C(1000000) * av_timegm(&tv);
} }
/** static int ftp_parse_entry_nlst(char *line, AVIODirEntry *next)
* @return 0 on success, negative on error, positive on entry to discard. {
*/ next->name = av_strdup(line);
static int ftp_parse_entry(char *mlsd, AVIODirEntry *next) return 0;
}
static int ftp_parse_entry_mlsd(char *mlsd, AVIODirEntry *next)
{ {
char *fact, *value; char *fact, *value;
av_dlog(NULL, "%s\n", mlsd); av_dlog(NULL, "%s\n", mlsd);
...@@ -914,6 +963,24 @@ static int ftp_parse_entry(char *mlsd, AVIODirEntry *next) ...@@ -914,6 +963,24 @@ static int ftp_parse_entry(char *mlsd, AVIODirEntry *next)
return 0; return 0;
} }
/**
* @return 0 on success, negative on error, positive on entry to discard.
*/
static int ftp_parse_entry(URLContext *h, char *line, AVIODirEntry *next)
{
FTPContext *s = h->priv_data;
switch (s->listing_method) {
case MLSD:
return ftp_parse_entry_mlsd(line, next);
case NLST:
return ftp_parse_entry_nlst(line, next);
case UNKNOWN_METHOD:
default:
return -1;
}
}
static int ftp_read_dir(URLContext *h, AVIODirEntry **next) static int ftp_read_dir(URLContext *h, AVIODirEntry **next)
{ {
FTPContext *s = h->priv_data; FTPContext *s = h->priv_data;
...@@ -951,7 +1018,7 @@ static int ftp_read_dir(URLContext *h, AVIODirEntry **next) ...@@ -951,7 +1018,7 @@ static int ftp_read_dir(URLContext *h, AVIODirEntry **next)
if (!*next) if (!*next)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
(*next)->utf8 = s->utf8; (*next)->utf8 = s->utf8;
ret = ftp_parse_entry(start, *next); ret = ftp_parse_entry(h, start, *next);
if (ret) { if (ret) {
avio_free_directory_entry(next); avio_free_directory_entry(next);
if (ret < 0) if (ret < 0)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment