#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
#include <errno.h>
+#include <ctype.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define fcntlsocket fcntl
#endif
+static int sendcmd(struct ftp *ftp, const char *fmt, ...);
static int handle_control(struct ftp *ftp);
static int handle_data(struct ftp *ftp, int s);
static void proc_control(struct ftp *ftp, const char *buf);
+static void cproc_pwd(struct ftp *ftp, int code, const char *buf, void *cls);
+static void cproc_cwd(struct ftp *ftp, int code, const char *buf, void *cls);
+
+
struct ftp *ftp_alloc(void)
{
struct ftp *ftp;
return -1;
}
+static int sendcmd(struct ftp *ftp, const char *fmt, ...)
+{
+ char buf[256];
+ va_list ap;
+
+ if(ftp->ctl < 0) {
+ return -1;
+ }
+
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+ strcat(buf, "\r\n");
+
+ return send(ftp->ctl, buf, strlen(buf), 0);
+}
+
static int handle_control(struct ftp *ftp)
{
int i, sz, rd;
return -1;
}
+static int respcode(const char *resp)
+{
+ if(!isdigit(resp[0]) || !isdigit(resp[1]) || !isdigit(resp[2])) {
+ return 0;
+ }
+
+ if(isspace(resp[3])) {
+ return atoi(resp);
+ }
+ if(resp[3] == '-') {
+ return -atoi(resp);
+ }
+ return 0;
+}
+
static void proc_control(struct ftp *ftp, const char *buf)
{
+ int code;
+
+ while(*buf && isspace(*buf)) buf++;
+
+ if((code = respcode(buf)) == 0) {
+ warnmsg("ignoring invalid response: %s\n", buf);
+ return;
+ }
+ if(code < 0) {
+ return; /* ignore continuations for now */
+ }
+
+ if(ftp->cproc) {
+ ftp->cproc(ftp, code, buf, ftp->cproc_cls);
+ ftp->cproc = 0;
+ return;
+ }
+
+ switch(code) {
+ case 220:
+ sendcmd(ftp, "user %s", ftp->user ? ftp->user : "anonymous");
+ break;
+ case 331:
+ sendcmd(ftp, "pass %s", ftp->pass ? ftp->pass : "foobar");
+ break;
+ case 230:
+ ftp->status = 1;
+ infomsg("login successful\n");
+ ftp_pwd(ftp);
+ ftp->modified = 1;
+ break;
+ case 530:
+ ftp->status = 0;
+ errmsg("login failed\n");
+ break;
+ }
}
int ftp_update(struct ftp *ftp)
return -1;
}
+int ftp_pwd(struct ftp *ftp)
+{
+ sendcmd(ftp, "pwd");
+ ftp->cproc = cproc_pwd;
+ return 0;
+}
+
int ftp_chdir(struct ftp *ftp, const char *dirname)
{
- return -1;
+ // TODO queue
+ sendcmd(ftp, "cwd %s", dirname);
+ ftp->cproc = cproc_cwd;
+ return 0;
+}
+
+static int get_quoted_text(const char *str, char *buf)
+{
+ int len;
+ const char *src, *end;
+
+ if(!(src = strchr(str, '"'))) {
+ return -1;
+ }
+ src++;
+ end = src;
+ while(*end && *end != '"') end++;
+ if(!*end) return -1;
+
+ len = end - src;
+ memcpy(buf, src, len);
+ buf[len] = 0;
+ return 0;
+}
+
+static void cproc_pwd(struct ftp *ftp, int code, const char *buf, void *cls)
+{
+ char *dirname;
+
+ if(code != 257) {
+ warnmsg("pwd failed\n");
+ return;
+ }
+
+ dirname = alloca(strlen(buf) + 1);
+ if(get_quoted_text(buf, dirname) == -1) {
+ warnmsg("pwd: invalid response: %s\n", buf);
+ return;
+ }
+
+ free(ftp->curdir_rem);
+ ftp->curdir_rem = strdup_nf(dirname);
+ ftp->modified = 1;
+}
+
+static void cproc_cwd(struct ftp *ftp, int code, const char *buf, void *cls)
+{
}
enum {FTP_DIR, FTP_FILE}; /* ftp_dirent type */
+enum {
+ FTP_PWD,
+ FTP_CHDIR,
+ FTP_MKDIR,
+ FTP_RMDIR,
+ FTP_DEL,
+ FTP_LIST,
+ FTP_RETR,
+ FTP_STORE
+};
+
+struct ftp_op {
+ int op;
+ char *arg;
+};
+
struct ftp_dirent {
char *name;
int type;
struct ftp {
int ctl, data; /* sockets */
+ int status;
+ char *user, *pass;
+
+ void (*cproc)(struct ftp *ftp, int code, const char *buf, void *cls);
+ void (*dproc)(struct ftp *ftp, const char *buf, int sz, void *cls);
+ void *cproc_cls, *dproc_cls;
+
char crecv[256];
int num_crecv;
char drecv[256];
int num_drecv;
- char *cwd;
+ char *curdir_rem, *curdir_loc;
struct ftp_dirent *dent;
int num_dent;
+
+ int modified;
};
struct ftp *ftp_alloc(void);
void ftp_free(struct ftp *ftp);
+void ftp_auth(const char *user, const char *pass);
+
int ftp_connect(struct ftp *ftp, const char *host, int port);
void ftp_close(struct ftp *ftp);
int ftp_handle(struct ftp *ftp, int s);
int ftp_update(struct ftp *ftp);
+int ftp_pwd(struct ftp *ftp);
int ftp_chdir(struct ftp *ftp, const char *dirname);
void tui_set_callback(struct tui_widget *w, int type, tui_callback func, void *cls);
+int tui_set_title(struct tui_widget *w, const char *s);
+const char *tui_get_title(struct tui_widget *w);
+
struct tui_widget *tui_window(const char *title, int x, int y, int w, int h);
struct tui_widget *tui_button(const char *title, int x, int y, tui_callback cbfunc, void *cbdata);
struct tui_widget *tui_list(const char *title, int x, int y, int w, int h, tui_callback cbfunc, void *cbdata);