13 #include <sys/select.h>
22 #define select select_s
26 int update_localdir(void);
28 int keypress(int key);
29 int parse_args(int argc, char **argv);
31 static struct ftp *ftp;
32 static struct tui_widget *uilist[2];
36 static char *host = "localhost";
39 static char curdir[PATH_MAX + 1];
40 static struct ftp_dirent *localdir;
43 int main(int argc, char **argv)
45 int i, numsock, maxfd;
50 if(parse_args(argc, argv) == -1) {
54 localdir = darr_alloc(0, sizeof *localdir);
55 getcwd(curdir, sizeof curdir);
58 if(!(ftp = ftp_alloc())) {
61 if(ftp_connect(ftp, host, port) == -1) {
73 uilist[0] = tui_list("Remote", 0, 0, 40, 23, 0, 0);
74 uilist[1] = tui_list("Local", 40, 0, 40, 23, 0, 0);
76 tui_focus(uilist[focus], 1);
87 numsock = ftp_sockets(ftp, ftpsock, sizeof ftpsock);
88 for(i=0; i<numsock; i++) {
89 FD_SET(ftpsock[i], &rdset);
90 if(ftpsock[i] > maxfd) maxfd = ftpsock[i];
98 tv.tv_sec = tv.tv_usec = 0;
101 if(select(maxfd + 1, &rdset, 0, 0, &tv) == -1 && errno == EINTR) {
106 if(FD_ISSET(0, &rdset)) {
107 if(proc_input() == -1) {
112 if(proc_input() == -1) {
117 for(i=0; i<numsock; i++) {
118 if(FD_ISSET(ftpsock[i], &rdset)) {
119 ftp_handle(ftp, ftpsock[i]);
136 struct ftp_dirent *ent;
137 unsigned int upd = 0;
141 remdir = ftp_curdir(ftp);
142 if(remdir && strcmp(tui_get_title(uilist[0]), remdir) != 0) {
143 tui_set_title(uilist[0], remdir);
147 if(ftp->modified & FTP_MOD_DIR) {
148 tui_clear_list(uilist[0]);
150 num = ftp_num_dirent(ftp);
151 for(i=0; i<num; i++) {
152 ent = ftp_dirent(ftp, i);
153 if(ent->type == FTP_DIR) {
154 sprintf(buf, "%s/", ent->name);
155 tui_add_list_item(uilist[0], buf);
157 tui_add_list_item(uilist[0], ent->name);
161 tui_list_select(uilist[0], 0);
163 ftp->modified &= ~FTP_MOD_DIR;
167 if(strcmp(tui_get_title(uilist[1]), curdir) != 0) {
168 tui_clear_list(uilist[1]);
169 num = darr_size(localdir);
170 for(i=0; i<num; i++) {
172 if(ent->type == FTP_DIR) {
173 sprintf(buf, "%s/", ent->name);
174 tui_add_list_item(uilist[1], buf);
176 tui_add_list_item(uilist[1], ent->name);
179 tui_list_select(uilist[1], 0);
180 tui_set_title(uilist[1], curdir);
184 if(tui_isdirty(uilist[0]) || upd & 1) {
187 if(tui_isdirty(uilist[1]) || upd & 2) {
192 int update_localdir(void)
197 struct ftp_dirent ent;
199 if(!(dir = opendir(curdir))) {
200 errmsg("failed to open directory: %s\n", curdir);
204 darr_clear(localdir);
205 while((dent = readdir(dir))) {
206 ent.name = strdup_nf(dent->d_name);
207 if(strcmp(dent->d_name, ".") == 0) continue;
209 if(stat(dent->d_name, &st) == 0) {
210 if(S_ISDIR(st.st_mode)) {
215 ent.size = st.st_size;
221 darr_push(localdir, &ent);
225 qsort(localdir, darr_size(localdir), sizeof *localdir, ftp_direntcmp);
233 while(poll_input(&ev)) {
236 if(keypress(ev.key.key) == -1) {
248 int keypress(int key)
259 tui_focus(uilist[focus], 0);
261 tui_focus(uilist[focus], 1);
265 tui_list_sel_prev(uilist[focus]);
268 tui_list_sel_next(uilist[focus]);
271 tui_list_sel_start(uilist[focus]);
274 tui_list_sel_end(uilist[focus]);
278 sel = tui_get_list_sel(uilist[focus]);
280 struct ftp_dirent *ent = ftp_dirent(ftp, sel);
281 if(ent->type == FTP_DIR) {
282 ftp_queue(ftp, FTP_CHDIR, ent->name);
287 if(localdir[sel].type == FTP_DIR) {
288 if(chdir(localdir[sel].name) == -1) {
289 errmsg("failed to change directory: %s\n", localdir[sel].name);
291 getcwd(curdir, sizeof curdir);
302 ftp_queue(ftp, FTP_CDUP, 0);
304 if(chdir("..") == 0) {
305 getcwd(curdir, sizeof curdir);
317 static const char *usage = "Usage: %s [options] [hostname] [port]\n"
319 " -h: print usage information and exit\n";
321 int parse_args(int argc, char **argv)
325 for(i=1; i<argc; i++) {
326 if(argv[i][0] == '-') {
327 if(argv[i][2] != 0) {
332 printf(usage, argv[0]);
346 if((port = atoi(argv[i])) <= 0) {
347 fprintf(stderr, "invalid port number: %s\n", argv[i]);
360 fprintf(stderr, "invalid argument: %s\n", argv[i]);
361 fprintf(stderr, usage, argv[0]);