13 #include <sys/select.h>
22 int update_localdir(void);
24 int keypress(int key);
25 int parse_args(int argc, char **argv);
27 static struct ftp *ftp;
28 static struct tui_widget *uilist[2];
32 static char *host = "localhost";
35 static char curdir[PATH_MAX + 1];
36 static struct ftp_dirent *localdir;
39 int main(int argc, char **argv)
41 int i, numsock, maxfd;
46 if(parse_args(argc, argv) == -1) {
50 localdir = darr_alloc(0, sizeof *localdir);
51 getcwd(curdir, sizeof curdir);
54 if(!(ftp = ftp_alloc())) {
57 if(ftp_connect(ftp, host, port) == -1) {
69 uilist[0] = tui_list("Remote", 0, 0, 40, 23, 0, 0);
70 uilist[1] = tui_list("Local", 40, 0, 40, 23, 0, 0);
72 tui_focus(uilist[focus], 1);
83 numsock = ftp_sockets(ftp, ftpsock, sizeof ftpsock);
84 for(i=0; i<numsock; i++) {
85 FD_SET(ftpsock[i], &rdset);
86 if(ftpsock[i] > maxfd) maxfd = ftpsock[i];
94 tv.tv_sec = tv.tv_usec = 0;
97 if(select(maxfd + 1, &rdset, 0, 0, &tv) == -1 && errno == EINTR) {
102 if(FD_ISSET(0, &rdset)) {
103 if(proc_input() == -1) {
109 for(i=0; i<numsock; i++) {
110 if(FD_ISSET(ftpsock[i], &rdset)) {
111 ftp_handle(ftp, ftpsock[i]);
128 struct ftp_dirent *ent;
129 unsigned int upd = 0;
133 remdir = ftp_curdir(ftp);
134 if(remdir && strcmp(tui_get_title(uilist[0]), remdir) != 0) {
135 tui_set_title(uilist[0], remdir);
139 if(ftp->modified & FTP_MOD_DIR) {
140 tui_clear_list(uilist[0]);
142 num = ftp_num_dirent(ftp);
143 for(i=0; i<num; i++) {
144 ent = ftp_dirent(ftp, i);
145 if(ent->type == FTP_DIR) {
146 sprintf(buf, "%s/", ent->name);
147 tui_add_list_item(uilist[0], buf);
149 tui_add_list_item(uilist[0], ent->name);
153 tui_list_select(uilist[0], 0);
155 ftp->modified &= ~FTP_MOD_DIR;
159 if(strcmp(tui_get_title(uilist[1]), curdir) != 0) {
160 tui_clear_list(uilist[1]);
161 num = darr_size(localdir);
162 for(i=0; i<num; i++) {
164 if(ent->type == FTP_DIR) {
165 sprintf(buf, "%s/", ent->name);
166 tui_add_list_item(uilist[1], buf);
168 tui_add_list_item(uilist[1], ent->name);
171 tui_list_select(uilist[1], 0);
172 tui_set_title(uilist[1], curdir);
176 if(tui_isdirty(uilist[0]) || upd & 1) {
179 if(tui_isdirty(uilist[1]) || upd & 2) {
184 int update_localdir(void)
189 struct ftp_dirent ent;
191 if(!(dir = opendir(curdir))) {
192 errmsg("failed to open directory: %s\n", curdir);
196 darr_clear(localdir);
197 while((dent = readdir(dir))) {
198 ent.name = strdup_nf(dent->d_name);
199 if(strcmp(dent->d_name, ".") == 0) continue;
201 if(stat(dent->d_name, &st) == 0) {
202 if(S_ISDIR(st.st_mode)) {
207 ent.size = st.st_size;
213 darr_push(localdir, &ent);
217 qsort(localdir, darr_size(localdir), sizeof *localdir, ftp_direntcmp);
225 while(poll_input(&ev)) {
228 if(keypress(ev.key.key) == -1) {
240 int keypress(int key)
251 tui_focus(uilist[focus], 0);
253 tui_focus(uilist[focus], 1);
257 tui_list_sel_prev(uilist[focus]);
260 tui_list_sel_next(uilist[focus]);
263 tui_list_sel_start(uilist[focus]);
266 tui_list_sel_end(uilist[focus]);
270 sel = tui_get_list_sel(uilist[focus]);
272 struct ftp_dirent *ent = ftp_dirent(ftp, sel);
273 if(ent->type == FTP_DIR) {
274 ftp_queue(ftp, FTP_CHDIR, ent->name);
279 if(localdir[sel].type == FTP_DIR) {
280 if(chdir(localdir[sel].name) == -1) {
281 errmsg("failed to change directory: %s\n", localdir[sel].name);
283 getcwd(curdir, sizeof curdir);
294 ftp_queue(ftp, FTP_CDUP, 0);
296 if(chdir("..") == 0) {
297 getcwd(curdir, sizeof curdir);
309 static const char *usage = "Usage: %s [options] [hostname] [port]\n"
311 " -h: print usage information and exit\n";
313 int parse_args(int argc, char **argv)
317 for(i=1; i<argc; i++) {
318 if(argv[i][0] == '-') {
319 if(argv[i][2] != 0) {
324 printf(usage, argv[0]);
338 if((port = atoi(argv[i])) <= 0) {
339 fprintf(stderr, "invalid port number: %s\n", argv[i]);
352 fprintf(stderr, "invalid argument: %s\n", argv[i]);
353 fprintf(stderr, usage, argv[0]);